Search code examples
phpapisymfonyfosrestbundlejmsserializerbundle

FOSRestBundle: partial response in function of attributes asked in the request


Context

I found a lot of questions about partial API response with FOSRest and all the answers are based on the JMS serializer options (exlude, include, groups, etc). It works fine but I try to achieve something less "static".

Let's say I have a user with the following attributes: id username firstname lastname age sex

I retrieve this user with the endpoint GET /users/{id} and the following method:

/**
 * @View
 *
 * GET /users/{id}
 * @param integer $user (uses ParamConverter)
 */
public function getUserAction(User $user) {
    return $user;
}

The method returns the user with all his attributes.

Now I want to allow something like that: GET /users/{id}?attributes=id,username,sex

Question

Did I missed a functionality of FOSRestBUndle, JMSserializer or SensioFrameworkExtraBundle to achieve it automatically? An annotation, a method, a keyword in the request or something else?

Otherwise, what is the best way to achieve it?

Code

I thought to do something like that:

/**
 * @View
 * @QueryParam(name="attributes")
 *
 * GET /users/{id}
 *
 * @param integer $user (uses ParamConverter)
 */
public function getUserAction(User $user, $attributes) {
    $groups = $attributes ? explode(",", $attributes) : array("Default");

    $view = $this->view($user, 200)
        ->setSerializationContext(SerializationContext::create()->setGroups($groups));

    return $this->handleView($view);
}

And create a group for each attribute:

use JMS\Serializer\Annotation\Groups;

class User {

    /** @Groups({"id"}) */
    protected $id;

    /** @Groups({"username"}) */
    protected $username;

    /** @Groups({"firstname"}) */
    protected $firstname;

    //etc
}

Solution

  • You can do it like that through groups, as you've shown. Maybe a bit more elegant solution would be to implement your own ExclusionStrategy. @Groups and other are implementations of ExclusionStrategyInterface too.

    So, say you called your strategy SelectFieldsStrategy. Once you implement it, you can add it to your serialization context very easy:

    $context = new SerializationContext();
    $context->addExclusionStrategy(new SelectFieldsStrategy(['id', 'name', 'someotherfield']));