Working with normalizers in Drupal 8

Entity Pilot makes extensive use of normalizers for handling dereferencing incoming content.

Normalizers are a key part of Drupal 8's serialization strategies and represent a flexible extension point for your module to interact with core APIs.

Read on to learn how your code can interact with Drupal's normalizing and denormalizing operations and influence what is output by the REST and Hal modules.

The serializer service

In Drupal 8 the serializer service is responsible for translating content to and from various representations of a given object. The serializer performs encoding/decoding, serializing/deserializing and normalizing/denormalizing. Each of these is a discrete operation that represents changing the format of an object, to and from and array, and to and from a string. The role of each operation is as follows:

Serializing comprises optional normalizing and encoding, whilst deserializing handles the reverse. A serialize operation takes an object or array, normalizes it as required and encodes it into a given format. Eg calling $serialzer->serialize($data, 'json'); takes care of first normalizing $data, and then encoding it to JSON whilst calling deserialize reverses the process.
Encoders are responsible for transforming data to and from a particular representation - eg Drupal core has encoders/decoders for JSON and XML. Encoding is the process of converting the given data into e.g. JSON whilst decoding transforms it back to the original format.
Normalizing is the process of converting an object into a series of arrays and scalars. For example calling $serializer->normalize($object, $format); handles converting $object into an array in the given format. Denormalizing reverses the process.

How normalizing works in Drupal 8

Normalizing works in Drupal 8 using a chain of responsibility (COR) and tagged services. Services tagged with 'normalizer' are detected and sorted according to their priority. Then when a normalize operation is requested from the serializer, it processes each normalizer in sequence until it finds one that applies. Complex objects might need to call back to the serializer to handle normalizing their sub-properties. For example the ContentEntityNormalizer in the HAL module (\Drupal\hal\Normalizer\ContentEntityNormalizer) has a normalize operation that calculates all of the fields and properties of an entity, and then calls the Serializer service again so that the fields and properties are normalized too.

Providing your own normalizers

The default normalizers in Drupal core handle transforming entities to and from various formats as well as dereferencing entity reference fields using UUIDs - to ensure the references point to valid content in the site.

But what happens if you need to alter how this works? Well thankfully the process is fairly simple. You need to define a new normalizer service in your services.yml file, tag it as a normalizer and give it a priority higher than the normalizer you want to replace. You can extend the existing one if you only need to override some of the logic, allowing you to call back to the parent. An example services.yml definition would look like so.

class: Drupal\my_module\Normalizer\EntityReferenceItemNormalizer
arguments: ['@rest.link_manager']
- { name: normalizer, priority: 10 }

Then simply implement your logic in the new class and you're done.


Chain or responsibility (COR) and tagged services are a common pattern in Drupal 8, similar approaches exist for dealing with breadcrumbs and theme negotiation, amongst others.

Like many other patterns in Drupal 8, taking the time to learn it for one system has applications in other systems.

Its great to see the degree of flexibility afforded by the serialization module in Drupal 8 core, it opens up many exciting possibilities for Drupal 8, including Entity Pilot.