Search code examples
yii2yii-rest

Yii2 REST API find by field


This is api url.

/api/web/v1/users/123

Find user by id. How to change rule to find by token, not by id?

Here is a rule:

            [
                'class' => 'yii\rest\UrlRule',
                'controller' => ['v1/users'],
                'tokens' => [
                    '{id}' => '<id:\\w+>'

                   // this does not work  
                   // '{token}' => '<token:\\w+>'
                ],
            ],

Solution

  • That {id} defined as a token is the one used by the built in yii\rest\ViewAction which code is this:

    class ViewAction extends Action
    {
        /**
         * Displays a model.
         * @param string $id the primary key of the model.
         * @return \yii\db\ActiveRecordInterface the model being displayed
         */
        public function run($id)
        {
            $model = $this->findModel($id);
            if ($this->checkAccess) {
                call_user_func($this->checkAccess, $this->id, $model);
            }
    
            return $model;
        }
    }
    

    $this->findModel($id) is defined under yii\rest\Action and it find models using their primary key(s). If you need to use a different token like {token} and find your model within a different attribute than its primary key then you'll need to override the view action inside your controller.

    Here is an example that should work when adding '{token}' => '<token:\\w+>' to your rules:

    class UserController extends ActiveController
    {
        ...
        public function actions()
        {
            $actions = parent::actions();
            unset($actions['view']);
            return $actions;
        }
    
        public function actionView($token){
            $modelClass = $this->modelClass;
            $model = $modelClass::find()->where(['token' => $token])->one();
    
            if ($model === null)
                throw new \yii\web\NotFoundHttpException("Uknown user having $token as token");
    
            return $model;
        }
    
    }
    

    Also note that you will need to change your $patterns to support the new inroduced one. Your final rules may look like this:

    'rules' => [
        [
            'class' => 'yii\rest\UrlRule', 
            'controller' => ['v1/users'],  
            'tokens' => [
                '{id}' => '<id:\\w+>',
                '{token}' => '<token:\\w+>'
            ]
            'patterns' => [
                'PUT,PATCH {id}' => 'update',
                'DELETE {id}' => 'delete',
                // {token} is assigned to $token when redirecting to view
                'GET,HEAD {token}' => 'view',
                'POST' => 'create',
                'GET,HEAD' => 'index',
                '{id}' => 'options',
                '' => 'options',
            ],
        ],
    ]