Problem/Motivation
We want to:
- Be compatible with JSON:API 2.x.
- Be compatible with JSON:API Extras 3.x.
- Have image styles on the image entities.
- Have image styles on the relationship items pointing to image entities.
- Have configurability based on the Consumer making the request.
- Refine the list of image styles on the relationship using JSON:API Extra's UI (not reinventing the wheel).
Proposed resolution
- Create a service to build the links for an image, given a list of configured image styles.
- Use Field Enhancers to provide field-level configurability.
- Override the entity normalizer for image entities following the same pattern in JSON:API Extras.
| Comment | File | Size | Author |
|---|---|---|---|
| #18 | 3027238--new-version--18.patch | 38.5 KB | e0ipso |
| #18 | 3027238--interdiff--4-18.txt | 2.51 KB | e0ipso |
| #9 | 3027238--interdiff--3-4.txt | 16.41 KB | e0ipso |
| #9 | 3027238--new-version--4.patch | 38.32 KB | e0ipso |
| #3 | 3027238--new-version--3.patch | 27.2 KB | e0ipso |
Comments
Comment #2
e0ipsoPasting from Slack.
Comment #3
e0ipsoFirst patch draft. This creates the output described above.
This doesn't adapt any of the tests, so expect red.
Comment #4
szeidler commentedThanks for your great effort @e0ipso.
I tested patch #3 with JSON:API 2.x and JSON:API Extras 3.x. It seems simply to work like a charm!
Derivatives for image fields on nodes are exposed directly. Derivatives for media (image) field on nodes are exposed when including the media field. Refining the image style list with JSON:API Extras also worked. Perfect!
Comment #5
wim leersComment #6
gabesulliceOverall, I like the idea. But, like you said, the ickiest bit is that the links are under the
metabit of the relationship object.I love the use of an extension link relation type. FWIW, those aren't actually serialized under the link
metaright now, since I have https://github.com/json-api/json-api/pull/1348 open, which would serialize it elsewhere.I see that you've got derivatives on the relationship object and on the included image, but they're not the same. I don't understand that.
Last thought: why use the key
linksas all? Why not have a links object with a key ofimageDerivatives? There's no particular spec reason it has to belinks. Having the camel-casing makes it profile-compatible and has the nice side-effect that it doesn't appear so blatantly "non-spec'd".Alternatively, you could have an
imageDerivativesobject, which itself has alinksobject. This gives you the most flexibility because it'll permit you to have non-link keys/values if they ever become necessary or desirable.Comment #7
gabesullicePassing thought:
If you could add
imageDerivativesas a computed property of theimagefield type (either by altering or extending), then it would work for REST, JSON:API and (presumably) GraphQL. You'd have to consider if that is worth the effort.Comment #8
e0ipsoThanks all for your feedback!
I was hoping that a client could then leverage a link parser module if we ensured links compliance. Do you think it's better to stick them out?
You can specify the image styles to apply for a given consumer. However since JSON:API Extras gives you extra configurability for fields, you can refine those on a field-by-field basis if necessary. TL;DR if you don't manually add the field enhancer to a file field you won't get field level image styles.
So why the field-level image styles? For better UX and performance. Typically images are hosted on other entities via relationships, so we should skip the includes for the most common task of all in that kind of relationship. That will lower parsing complexity, reduce response size and improve server performance.
So why not only add those in the entity reference then? Because then you can't select an entity with its image styles. IIRC the core patch for image styles misses this.
I had the same temptation. I think the core patch takes this approach. The problem is that you will end up generating those image style URLs (a potentially costy operation) whenever you are loading the host entity, which can lead to very bad performance (given the right combination of popular modules).
Would you be kind enough to provide an example?
Comment #9
e0ipsoThis should be green now.
Comment #10
gabesulliceI think you might have misunderstood my first question about "why use the key "links" as all?" I didn't mean, don't use links, I meant don't use the key name "links". Just use the key name
imageDerivatives, the value for that key would be identical to a links object and a parser should handle it just fine.So, this:
Instead of this:
And finally, "an imageDerivatives object, which itself has a links object":
^ This last one is my favorite because you could have a profile for it + you still have the key name
linkswhich will be more familiar to users + it's more resilient to change (f.e. you could add a"recommendedDerivative": "thumbnail"w/o breaking BC)Maybe
derivativeshould be a fragment (i.e./relation-types/#derivative)instead of a path segment. I'm just thinking about documenting these link relations in the future and that might be a nicer pattern. WDYT?❤️
Comment #11
dustinleblancJust chiming in, I tried applying these patches on the module to get rolling with contenta 3.0^ and for some reason, I am not getting any image styles in the responses. My Requests are making use of the includes key and the sub-requests module to cut down on round trips, not sure if that is impacting my results.
Comment #12
dustinleblancJust spun up a vanilla D8 install with JSON API/Extras and consumer image styles so I can test without our constraints. This works there when I use just a node and an image on that node. In our actual use case, there is a paragraph being included and an image on that paragraph. I just confirmed that if I fetch the paragraph directly, rather than using an includes chain, everything works as it should.
For reference, here is my request structure of the _non_ working request
Note that this request works like a charm to get me parsable data with all my relationships, except the issue with getting the image styles. I refactored this from a previous JSONAPI 1.x version that used a lot more requests and was able to pull the images.
I think what is required to get the total magic package together is to somehow allow these resources to get transformed when they are included via a more complex include chain.
Comment #13
dustinleblancThe plot thickens!
I had to make sure to set
"X-CONSUMER-ID"as a header inside each sub-request.I now have all the magicks, thanks for your hard work on this @e0ipso!
Comment #14
dustinleblancThe plot thickens!
I had to make sure to set
"X-CONSUMER-ID"as a header inside each sub-request.I now have all the magicks, thanks for your hard work on this @e0ipso!
Comment #15
dustinleblancThe plot thickens!
I had to make sure to set
"X-CONSUMER-ID"as a header inside each sub-request.I now have all the magicks, thanks for your hard work on this @e0ipso!
Comment #16
e0ipso@dustinleblanc ah! Yes, that makes sense. Thanks for digging in and looping back here. How do you think we can improve our docs so the next dev doesn't get tripped by that?
Comment #17
dustinleblanc@e0ipso, I think that the new 3.x branch should just include a section on sub-requests in the readme. I'd be happy to help with that. As a starter something like:
I'd be happy to submit a patch once the language is good and there is a 3.x branch on D.O or GH to submit it to (I think trying to add to your existing patch here might be confusing?).
Thanks again! It's taking me a bit to wrap my head around how to 'do this right', but modules like this one make the end result much better.
Comment #18
e0ipsoThanks for the feedback in #10 @gabesullice. I like your suggestions. This patch implements them.
I have not run tests locally. If tests pass, I'll commit to 3.x.
Comment #19
e0ipso@dustinleblanc thanks for that paragraph! I'm happy to get that in. Would you mind opening a new ticket for it?
Comment #21
e0ipsoI pushed this to
8.x-3.x. Let's follow up on any lingering concerns in new issues.Comment #22
wim leersI'm surprised this suddenly got committed, with tests failing :(
Most importantly, it's not clear to me why
ImageEntityNormalizeris still needed, why isn't a@FieldEnhancerplugin alone not enough?