How to implement your own fields inclusion rules with JMS Serializer
A common good practice in REST API is to allow clients to specify a list of fields the server has to respond in the resources representation, allowing lighter responses and more efficient bandwidth usage. This is even a recommendation in JSON API, so today I’ll show you how you can implement this inside your PHP projets using the JMS Serializer (via Symfony2 or not).
Section intitulée introducing-exclusionstrategyIntroducing ExclusionStrategy
We gonna dig in the code a little, and see how to use the ExclusionStrategy. You may not know, but you’ve surely already used it, as it’s used by the @Groups and @Version annotations. They are driven by the same interface: ExclusionStrategyInterface.
interface ExclusionStrategyInterface
{
public function shouldSkipClass(ClassMetadata $metadata, Context $context);
public function shouldSkipProperty(PropertyMetadata $property, Context $context);
}
The two methods names speak for themselves:
- shouldSkipClass: Whether the class should be skipped;
- shouldSkipProperty: Whether the property should be skipped.
As you can see the first argument is a [Class|Property]Metadata from the great Metadata library, so you get all the annotations and values from the currently targeted class or property.
Section intitulée fields-white-list-the-right-wayFields white list the right way
By default, our resources must have a view with all the allowed fields, this is the role of Groups or Exclude, you can chose the exclusion strategy of your choice:
class Pony
{
/**
* @Serializer\Groups({"Default"})
*/
private $id;
/**
* @Serializer\Groups({"Default", "MyCustomViewName"})
*/
protected $title;
/**
* @Serializer\Groups({"Default"})
*/
protected $body;
/**
* @Serializer\Groups({"Admin"})
*/
protected $viewCount;
Then comes the Fields exclusion strategy. We need our controllers to tell the Serializer “Hey bro, please only include id and body in the response, the client only asked for those”. Holding this information is the role of the SerializationContext, a class knowing where we are, which format, what are the exclusion strategies, should we serialize null values…
Let’s call the serializer with a custom context:
$context = new SerializationContext();
$groups[] = 'Default';
$context->setGroups($groups);
$serializer->serialize(new Pony(), 'json', $context);
With this code my Pony id, title and body fields will be serialized. This is our API default view and we now want to filter by a end-user field list.
We can add our new exclusion strategy on the context:
$fieldList = ['id', 'title'];
$context->addExclusionStrategy(
new FieldsListExclusionStrategy($fieldList)
);
The code is pretty simple:
namespace Acme\Bundle\ApiBundle\Serializer\Exclusion;
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Context;
class FieldsListExclusionStrategy implements ExclusionStrategyInterface
{
private $fields = array();
public function __construct(array $fields)
{
$this->fields = $fields;
}
/**
* {@inheritDoc}
*/
public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext)
{
return false;
}
/**
* {@inheritDoc}
*/
public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext)
{
if (empty($this->fields)) {
return false;
}
$name = $property->serializedName ?: $property->name;
return !in_array($name, $this->fields);
}
}
This is a very straightforward example, on a real world API, depth handling should also be considered because we always want first level node, whatever their names are, so we can add something like this:
// Keep first level
if ($navigatorContext->getDepth() == 1) {
return false;
}
That’s it! Our JSON representation is now only displaying id and title, and as this is an exclusion, there is no way to add a field already excluded by another strategy.
Section intitulée you-can-do-moreYou can do more
Implementing the whole JSON API specification (with the fields[TYPE] notation) would be more related on your model and choices so we do not cover it here. ExclusionStrategy are a powerful tool and you can do a lot of logic in it, adding your own annotations, making it a service…
Hope you liked this quick article, happy coding!
Commentaires et discussions
Ces clients ont profité de notre expertise
Nous avons réalisé la refonte du site de l’agence Beautiful Monday en utilisant nos compétences HTML5/CSS3 côté front-end, et le framework Symfony2 côté back-end. Afin de s’afficher correctement sur n’importe quel appareil, le site est entièrement responsive. La partie intégration a été effectuée avec un grand soin, en respectant parfaitement la maquette…
Pour améliorer les performances et la pertinence des recherches sur le site e-commerce, JoliCode a réalisé un audit approfondi du moteur Elasticsearch existant. Nous avons optimisé les processus d’indexation, réduisant considérablement les temps nécessaires tout en minimisant les requêtes inutiles. Nous avons également ajusté les analyses pour mieux…
Dans le cadre d’une refonte complète de son architecture Web, le journal en ligne Mediapart a sollicité l’expertise de JoliCode afin d’accompagner ses équipes. Mediapart.fr est un des rares journaux 100% en ligne qui n’appartient qu’à ses lecteurs qui amène un fort traffic authentifiés et donc difficilement cachable. Pour effectuer cette migration, …