Mark
Mark

Reputation: 59

How to implement Filtering on YII restful GET api?

I am working on Restful APIs of Yii.

My controller name is ProductsController and the Model is Product.

When I call API like this GET /products, I got the listing of all the products.

But, now I want to filter the records inside the listing API.

For Example, I only want those records Which are having a product name as chairs. How to implement this? How to apply proper filtering on my Rest API. I am new to this. So, I have no idea how to implement this. I also followed their documentation but unable to understand.

May someone please suggest me a good example or a way to achieve this?

Upvotes: 2

Views: 2689

Answers (1)

Bizley
Bizley

Reputation: 18021

First of all you need to have validation rules in your model as usual.

Then it's the controllers job and depending on the chosen implementation I can give you some hints:


If your ProductsController extends yii\rest\ActiveController

Basically the easiest way because almost everything is already prepared for you. You just need to provide the $modelClass there and tweak actions() method a bit.

public function actions()
{
    $actions = parent::actions();

    $actions['index']['dataFilter'] = [
        'class' => \yii\data\ActiveDataFilter::class,
        'searchModel' => $this->modelClass,
    ];

    return $actions;
}

Here we are modifying the configuration for IndexAction which is by default responsible for GET /products request handling. The configuration is defined here and we want to just add dataFilter key configured to use ActiveDataFilter which processes filter query on the searched model which is our Product. The other actions are remaining the same.

Now you can use DataProvider filters like this (assuming that property storing the product's name is name):

  • GET /products?filter[name]=chairs will return list of all Products where name is chairs,
  • GET /products?filter[name][like]=chairs will return list of all Products where name contains word chairs.

If your ProductsController doesn't extend yii\rest\ActiveController but you are still using DataProvider to get collection

Hopefully your ProductsController extends yii\rest\Controller because it will already benefit from serializer and other utilities but it's not required.

The solution is the same as above but now you have to add it by yourself so make sure your controller's action contains something like this:

$requestParams = \Yii::$app->getRequest()->getBodyParams(); // [1]
if (empty($requestParams)) {
    $requestParams = \Yii::$app->getRequest()->getQueryParams(); // [2]
}

$dataFilter = new \yii\data\ActiveDataFilter([
    'searchModel' => Product::class // [3]
]);
if ($dataFilter->load($requestParams)) {
    $filter = $dataFilter->build(); // [4]
    if ($filter === false) { // [5]
        return $dataFilter;
    }
}

$query = Product::find();
if (!empty($filter)) {
    $query->andWhere($filter); // [6]
}

return new \yii\data\ActiveDataProvider([
    'query' => $query,
    'pagination' => [
        'params' => $requestParams,
    ],
    'sort' => [
        'params' => $requestParams,
    ],
]); // [7]

What is going on here (numbers matching the code comments):

  1. We are gathering request parameters from the body,
  2. If these are empty we take them from the URL,
  3. We are preparing ActiveDataFilter as mentioned above with searched model being the Product,
  4. ActiveDataFilter object is built using the gathered parameters,
  5. If the build process returns false it means there is an error (usually unsuccessful validation) so we return the object to user to see list of errors,
  6. If the filter is not empty we are applying it to the database query for Product,
  7. Finally we are configuring ActiveDataProvider object to return the filtered (and paginated and sorted if applicable) collection.

Now you can use DataProvider filters just as mentioned above.


If your ProductsController doesn't use DataProvider to get collection

You need to create your custom solution.

Upvotes: 7

Related Questions