Before
In Drupal 8.0, 8.1 and 8.2, all serialized values in the JSON, HAL+JSON and other formats are strings. Even integers and booleans. In other words, when requesting an article in JSON format, you'd get something like:
{
title: 'this is a string and it makes sense',
published: '1',
rating: '7',
sticky: '0'
}
title
is a string and it makes sensepublished
is a boolean "true" but it's serialized to'1'
instead oftrue
rating
is a rating from 1 to 10, but it's serialized to'7'
instead of7
sticky
is a boolean "false" but it's serialized to'0'
instead offalse
This is undesirable developer experience for consumers of serialized data (for example, decoupled applications) and requires additional conversions.
After
In Drupal 8.3, booleans are serialized to booleans, and integers are serialized to integers:
{
title: 'this is a string and it makes sense',
published: true,
rating: 7,
sticky: false
}
Backwards compatible: existing sites can opt in to the old behavior
All sites, including existing sites get the new behavior by default, which means they may have backwards-compatibility breaks if they expect all data types to be returned as strings.
Sites can opt in to keep the old behavior by changing the bc_primitives_as_strings
key's value from false
to true
in serialization.settings
configuration using one of the following mechanisms:
- Use the Configuration API in custom module or integration code.
- Use Drush:
drush config-set serialization.settings bc_primitives_as_strings TRUE
- Use configuration override
This backwards compatibility layer will be maintained until Drupal 9; in Drupal 9.0 it will be dropped.
Workarounds for individual applications
In some cases, a site may still require string values for a certain serialization format, when the parent site has not enabled the BC layer. This may occur if you have two decoupled clients using different serialization formats. One of the clients may handle the new behavior correctly while the other may not. In this case a site may cast values to strings for one serialization format only as a hotfix until the client is updated to handle the proper data types.
Below is an example of how you could accomplish this in a module to provide a temporary workaround if the site needed the 'json'
format only use string values:
In example.services.yml
# Override the PrimitiveDataNormalizer to allow uncasted values for select formats.
serializer.normalizer.primitive_data.uncasted:
class: Drupal\example\Normalizer\UncastedPrimitiveDataNormalizer
# The PrimitiveDataNormalizer uses priority 5.
tags:
- { name: normalizer, priority: 10 }
example/src/Normalizer/UncastedPrimitiveDataNormalize.php
namespace Drupal\example\Normalizer;
use Drupal\serialization\Normalizer\PrimitiveDataNormalizer;
/**
* Overrides the PrimitiveDataNormalizer to use the uncasted (string) values.
*
* This change means values will be retrieved as strings, matching the behavior
* of the JSON output before the PrimitiveDataNormalizer was added to
* the system in Drupal 8.3.
*/
class UncastedPrimitiveDataNormalizer extends PrimitiveDataNormalizer {
/**
* {@inheritdoc}
*/
protected $format = ['json'];
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = array()) {
return $object->getValue();
}
}