phpsymfony4api-platform.com

How can I use API Platform filters in YAML?


First of all, I want to inform you that I already read the docs about the problem I'm having today, and I also made a search on StackOverflow and Google, but didn't find a proper solution.

I am building a Customer Relationship Management API for practice sake with Symfony 4 and API Platform. I already learned a lot about API Platform, and even though I could have used annotations for resources configuration, I forced myself to use YAML in order to learn more about it.

So, I have a Customer resource which has several attributes: id, firstname, lastname, emailAddress, company, createdAt, updatedAt, and owner. My goal is to add a SearchFilter on this resource (in YAML) and add most of the attributes as properties of this filter.

I already tried the solution given here: https://github.com/api-platform/core/issues/1755. The problem is that I can't manage to make it work. In services.yaml, I see that you can add arguments, but I don't know what equivalent you can find in annotations...

In config/services.yaml:

# filters
    app.my_filter:
        parent: 'api_platform.doctrine.orm.search_filter'
        tags: ['api_platform.filter']
        autowire: false
        autoconfigure: false
        public: false

In resources/customer.yaml:

App\Entity\Customer:
    collectionOperations:
        get:
            normalization_context:
                groups: ['Customer:Get']
            filters: ['app.my_filter']

What I intend to is something similar to this with annotations in src/Entity/Customer.php:

/**
 * @ApiResource
 *
 * [...]
 *
 * @ApiFilter(SearchFilter::class, properties={
 *     "firstname": "partial",
 *     "lastname": "partial",
 *     "emailAddress": "partial",
 *     "company": "partial"
 * })
 */
class Customer
{
...
}

I hope that you'll be able to help and that my problem is clearly explained. If not, please tell me and I'll do my best to give your more details.


Solution

  • I found a solution to my problem. It appears the API Platform docs wasn't too far away from the answer after all! After trying for some time in the resource configuration file, I finally decided to give a chance to the services.yaml file. I was greatly helped on this github issue. So, here's what I did.

    Step 1 - In services.yaml:

    # filters
        app.customer_resource.search_filter:
            parent:        'api_platform.doctrine.orm.search_filter'
            arguments:     [ { 'firstname': 'partial', 'lastname': 'partial', 'emailAddress': 'partial', 'owner.emailAddress': 'exact' } ]
            tags:          [ { name: 'api_platform.filter', id: 'customer.search_filter' } ]
            autowire:      false # required, explained below
            autoconfigure: false # required, explained below
    

    Note 0: the autowire and autoconfigure arguments are required here, otherwise you'll get an error:

    Attribute "autowire"/"autoconfigure" on service "app.customer_resource.search_filter" cannot be inherited from "_defaults" when a "parent" is set. Move your child definitions to a separate file or define this attribute explicitly in [...] (which is loaded in resource "[...]").

    Note 1: I noticed the most important element here is the "id" element of the "tags" argument. While I was looking for a solution, I discovered vendor/api-platform/core/src/Swagger/Serializer/DocumentationNormalizer::getFilter(), which indicates you have to give a filter id in order to make it work. See for yourself in step 2.

    Step 2 - In your resource config file (mine is in config/resources/customer.yaml)

    App\Entity\Customer:
        collectionOperations:
            get:
                filters: ['customer.search_filter']
    
        # ...
    

    I just added the filter for the GET collection operation by using the (like I said) important filter ID. So, this fixes my issue. BUT if someone out there has a better/simpler solution, I'd be glad to know it.

    Screenshot: What the API looks like when SearchFilter is in place