Active
Project:
Drupal core
Version:
main
Component:
serialization.module
Priority:
Normal
Category:
Plan
Assigned:
Unassigned
Reporter:
Created:
27 Sep 2015 at 12:53 UTC
Updated:
24 May 2022 at 07:58 UTC
Jump to comment: Most recent
Issues like #2575741: Priority of serialialization EntityReferenceFieldItemNormalizer must be lower than the one from hal show that relying on the priority to just sort the services and pick the first match is very problematic. You need to get one weight wrong and everything explodes completely if you end up with a combination of normalizers or denormalizers that don't play nicely together.
Somehow pick the most specific match, not just the first that we find. Avoid relying on an arbitrary list of priorities. But that system is actually Symfony, so I'm not sure what we can do about it.
Comments
Comment #2
wim leersComment #5
Grayside commentedA few things I've thought about in some of my serializer work:
Comment #6
damiankloip commentedNice write up! This should be useful.
- The REST formats stuff, you mean you would like more granular control over what formats are allowed on specific routes/actions? Either way, seems slightly outside of the serializer itself.
- Yes, this is one of the things we've talked about before. Doing something that checks formats for normalizers. The trouble (or benefit) of the symfony serializer is that it relies on supportsNormalization() to check data and/or format. So it needs to iterate in order to find the first match. We could, if we didn't use Symfony anymore, could do something similar to our access checking system, where we have the notion of both a static and dynamic way to check if a normalizer applies based on format.
- What issues are you hitting around the loop prevention? I mean if we needed to, we could add the circular reference checks ourselves, like the Symfony normalizers do. Is that what you mean?
Comment #7
Grayside commentedFor example, the description formats associated with Schemata will never be all that interesting with any of the content type resources unless I change the way Schemata interacts with REST. Why should inapplicable formats be offered in the REST UI for each resource? While this is outside the serializer, it goes to whether or not formats should have a more explicit relationship to the types of structures they transform. The answer might be "this is outside of scope, but maybe we should have a helper service that produces lists of viable formats for a given object to help build better UIs.
I have created a customized version of the hal_json format which recursively embeds referenced entities and certain cases of back-references. On top of that, I am doing some property exclusion and renaming to create a more approachable design for integration of these REST resources by non-Drupal developers. This has raised two problems:
Didn't mean to raise the caching issues here as I think it's out of context, but I think it's helpful when thinking about the issues around when circular references are problematic.
Comment #8
wim leersWould it not make more sense for the Schemata module to not provide a REST resource plugin, precisely because it cannot ever offer >1 format? Then you can just ensure that your module provides one route, that cannot be modified via config.
The Acquia Content Hub module struggles with a similar need. I opened #2822201: Allow contrib modules to deploy REST resources by creating routes, removing the need for config entities in that special case for that use case. It'd be great to have two modules using this capability.
Comment #9
Grayside commentedSchemata is going to drop rest plugins for routing, but its core architecture is built around serialization formats, one for each schema standard as applied to a "normal" format. So there is a "JSON Schema for HAL" module which is mostly made of normalizers.
I assemble the data needed to describe another resource then transform it into different serialized formats. Seems like a perfect fit.
Comment #10
wim leersAwesome :)
Comment #11
damiankloip commentedAs an intermediate step, before we consider rolling our own serializer (which might actually be an ideal endgame considering cacheablility/bubbleable metadata etc..) I think we should try to implement a serializer instance PER FORMAT. We could instantiate each instance with the normalizers that are applicable only. This would make everyones lives much easier. We avoid the global normalizer rat race that we currently have. We could then have some kind of ChainSerializer that delegated to the correct serializer instance.
Comment #12
wim leers#11: AMEN.
In fact, @damiankloip and I discussed that very thing in IRC yesterday, referring to #2800873-59: Add XML GET REST test coverage, work around XML encoder quirks:
Comment #13
damiankloip commentedOr maybe even just some ChainNormalizer class could also solve the problem.
Comment #14
wim leersHm, how do you envision that would work?
Comment #15
damiankloip commentedIt could essentially group normalizers, so you would have a ChainNormalizer for hal, that would always run first if the format was hal (so it would first only check the format before passing on to the child normalizers contained within it), then fall back to default ones. Something like that. Haven't thought it through completely, just bouncing ideas.
Comment #16
wim leersThat's an interesting direction for sure. I like it.
Comment #17
Grayside commentedSomething I may have mentioned above, but wanted to underscore: we have lots of ways to modify an existing format, but if you wanted to create a new format based on the normalizers for an existing one, things get dicey pretty fast. I've done this a couple different ways, both bad:
1. Created a trait to override the formats property or related support methods, then extend every normalizer I want to use into my format, using the trait as a fake base class. This sometimes causes a bad break in the magic of normalizers, which lets you end-run certain aspects of it's recursive nature by calling parent methods that get you out of the current data structure assumption.
2. Created a normalizer in which I did something to the effect of:
$normalized = $this->serializer->normalize($entity, 'hal_json', $context);then hacked on top of the normalized result to correct any minor issues.From a customization standpoint, I would love to be able to declare a format and have the format reference normalizers it should use. That way if I wanted my custom
application/vnd.example.com.hal+jsonI can ditch a lot of awkward boilerplate and skip some procedural workarounds.Comment #19
wim leersYet another reason why we need this: #2841027: JSON API format should only be used on JSON API routes, but can currently also be used for REST resources.
Comment #21
wim leersThis issue was mentioned in a Twitter discussion. In that discussion, dawehner mentioned a potential alternative: http://jmsyst.com/libs/serializer.
(See https://twitter.com/da_wehner/status/889970150836981760.)
Comment #22
Grayside commentedI haven't had a chance to do a review of http://jmsyst.com/libs/serializer, but wanted to illustrate/underscore some use cases I've been thinking about with the Schemata project.
My current thinking is that this sort of Drupal-ly UI building is better served by creating a Schema Type plugin to serve as a metadata proxy for the collection of normalizers. Even if we could include this kind of information directly from encoders or normalizers, neither of those is 1:1 for the number of supported formats. It still seems awkward to create a plugin type largely for annotation collection.
Comment #32
mxh commentedJust want to throw the decorator pattern in the ring. It may not be helpful at all regarding this issue, but it's a pattern that's quite often forgotten but Symfony supports this pattern natively besides priorities for services.