Contributor tasks needed
Task Novice task? Contributor instructions Complete?

Problem/Motivation

Symfony's Serializer chooses the Normalizers to use based on the format. This makes it possible to represent the data differently based on media type. For example, the JSON-LD Normalizer gives each entity "@id" and "@type" keys before passing it to the Encoder. This is part of the JSON-LD contract, and if a parser understands JSON-LD, it knows what these keys mean.

Unfortunately, there are many times when a contract isn't expressed via media type. For example, within the past year the Internet-Draft for profile was introduced, and there are some APIs which communicate their contract simply using human-readable documentation (e.g. the Stormpath API, which uses "href" where JSON-LD uses "@id").

Proposed resolution

Instead of having one Serializer registered with the container, register a Serializer for each contract. For example, serializer.jsonld would the the serializer for the JSON-LD contract, while serializer.json.stormpath would be the serializer for the Stormpath API contract. This way modules which want to use a particular contract can get the serializer for that contract.

REST module would simply use the media type based contracts. So it would use serializer.json or serializer.xml. If a site wanted to use a more specific contract for all of their JSON responses, they would simply switch out the serializer.json service.

Comments

Anonymous’s picture

Component: base system » serialization.module

Moving to component.

fago’s picture

REST module would simply use the media type based contracts. So it would use serializer.json or serializer.xml. If a site wanted to use a more specific contract for all of their JSON responses, they would simply switch out the serializer.json service.

What exactly would that change compared to now? I mean you could already register your own serializer service based on an arbitrary name and manually use it?

For switching out the json service, I'd just replace it with my own?

Anonymous’s picture

I changed my mind about how to handle it a bit. If we override Serializer, we can change how the normalizerCache is built to include the concept of contracts. This means it could still all be handled with one Serializer. I'm not sure whether it's a great idea, but worth exploring. I plan to post a patch.

I mean you could already register your own serializer service based on an arbitrary name and manually use it?

But you would have no way of having it used by the rest of the system... unless you replace each place where the rest of the system uses serialize(). Basically, this would mean that our core system couldn't handle the profiles. Profiles are a "lightweight and runtime-capable mechanism that allows servers and clients to be more explicit in how a specific instance of a media type represents concepts that are not defined by the media type itself, but by additional conventions (the profile processing rules and semantics)."

For example, if you POST something to a REST route that has the Content-Type application/json; profile=http://example.com/my-profile, the profile parameter does not make it to the serialization system, so you loose out on the capabilities it provides.

clemens.tolboom’s picture

This seems similar to #1927024: Pass Link headers into Serializer regarding adding context to the serializers.

Is symfony capable to extract the profile from Content-Type application/json; profile=http://example.com/my-profile? I guess so as running with a profile added does not harm curl --user admin:admin --header 'Accept: application/json; profile=http://example.com/my-profile' --request GET http://drupal.d8/node/1

Is 'executing' a profile similar to #2339795: Add "REST modes", just like we have "view modes" and "form modes" AND depth argument to reduce # of requests

Wim Leers’s picture

Version: 8.0.x-dev » 8.1.x-dev
Category: Task » Feature request

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Grayside’s picture

Symfony's ContentTypeMimeTypeGuesser prevents extracting attributes off the Content-Type header. Not sure that matters anymore given the switch to the _format query string.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

Issue summary: View changes
Status: Active » Closed (works as designed)

Everything described in the issue summary is already solved by the "format" abstraction. Each format can have its own normalization. In the example of the IS:

  • the JSON-LD contract would use the LD normalizer and the JSON encoder
  • the Stormpath API contract would use the Stormpath normalizer and the JSON encoder

All of this would still use the same \Symfony\Component\Serializer\Serializer (serializer) service; the serializer picks the appropriate normalizer services and encoder services. This is already how serialization.services.yml and hal.services.yml specify their own normalizers for a particular object type, and both reuse the same encoder class.


#3 talks about the concept of profiles. That would indeed not be supported. But let's be honest; the Symfony Serialization system that we adopted is already ill-equipped to deal with the complex object hierarchies that Drupal uses for entities and fields. It's already a pain with just json and hal_json. Having different flavors of hal_json on top of that would make it utterly incomprehensible and unmaintainable.
EDIT: see #2575761: Discuss a better system for discovering and selecting normalizers for how painful the current system is.

Also, until now, the concept of profiles has not been widely adopted. In fact, I've never ever heard about it in the year of fixing REST technical debt. So I think it's safe to say that for now, it's purely academic — there's no real world adoption nor demand.

If you want such profiles, then just define a hal_json_my_profile format, and the normalizers that are the same as for hal_json you use service aliasing, for the ones you want to override, you define custom normalizer services. Done.


In four years, there's nobody who has asked for this. Therefore closing this.