Search code examples
symfonysymfony4fosrestbundle

Best practice - How to respond with different entity views to improve performance in a RESTful API (Symfony 4)


When listing an using a REST index endpoint I would like to have different outputs for performance reasons.

ex: on the same GET path for CRUD indexing
- List of Entities with all associations
- List of Entities with some associations
- List of Entities with just some basic fields

This would be used for listing entities for a detailed view with statistics or just listing them for a drop down selector.

Possible Solution 1: I can do this in the controller by returning an object where I customize all the fields based on a query parameter - but then my controllers become very fat because listing all the required fields can be 20-30 fields per object. (basically giving up on the benefit of a serializer doing this automatically based on the type of the entity)

return [
   [
     'id' => $event->getId(),
     'name' => $event->getName(),
      ...
     'order_count' => $orderRepository->getOrderCountForEvent($event->getId())         
   ],
   ...
]

Possible Solution 2: I could define transform functions in the repository for the different views and filters that I want to return.

public function transform(Event $event, $type = 'shortlist')
{
    $view = null;

    switch($type) {
        case 'shortlist':
            $view = [
                'id'    => $event->getId(),
                'name'  => $event->getName(),
                'participants' => $orderRepository->getParticipantCountForEvent($event->getId()),
                 ...
            ];
        break;
        default:
            ... // all fields
        break
    }        

    return $view;
}

Are there any better / cleaner solutions? Most tutorials are only dealing with simple entities with simple relations and their CRUD implementations are very basic where they simply fetch every field and pass it to a serializer.


Solution

  • Maybe you are looking for the Symfony serializer, which has the feature of choosing fields you render.

    Example from the doc:

    use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
    use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
    use Symfony\Component\Serializer\Serializer;
    
    class User
    {
        public $familyName;
        public $givenName;
        public $company;
    }
    
    class Company
    {
        public $name;
        public $address;
    }
    
    $company = new Company();
    $company->name = 'Les-Tilleuls.coop';
    $company->address = 'Lille, France';
    
    $user = new User();
    $user->familyName = 'Dunglas';
    $user->givenName = 'Kévin';
    $user->company = $company;
    
    $serializer = new Serializer([new ObjectNormalizer()]);
    
    $data = $serializer->normalize($user, null, [AbstractNormalizer::ATTRIBUTES => ['familyName', 'company' => ['name']]]);
    // $data = ['familyName' => 'Dunglas', 'company' => ['name' => 'Les-Tilleuls.coop']];
    

    See documentation here: https://symfony.com/doc/current/components/serializer.html#selecting-specific-attributes