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
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?
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
}
My implementation based on Igor's answer:
ExlusionStrategy:
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Context;
class FieldsExclusionStrategy implements ExclusionStrategyInterface {
private $fields = array();
public function __construct(array $fields) {
$this->fields = $fields;
}
public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext) {
return false;
}
public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext) {
if (empty($this->fields)) {
return false;
}
if (in_array($property->name, $this->fields)) {
return false;
}
return true;
}
}
Controller:
/**
* @View
* @QueryParam(name="fields")
*
* GET /users/{id}
*
* @param integer $user (uses ParamConverter)
*/
public function getUserAction(User $user, $fields) {
$context = new SerializationContext();
$context->addExclusionStrategy(new FieldsExclusionStrategy($fields ? explode(',', $fields) : array()));
return $this->handleView($this->view($user)->setSerializationContext($context));
}
Endpoint:
GET /users/{id}?fields=id,username,sex
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With