For a project I'm working on we need to be able to obtain the JSON representation of an entity so it can be uploaded via Guzzle to a 3rd party system. I'm going to document what I work out.
| Comment | File | Size | Author |
|---|---|---|---|
| #44 | 2874509-42.patch | 10.79 KB | dawehner |
| #42 | interdiff-2874509.txt | 3.02 KB | dawehner |
| #42 | 2874509-42.patch | 10.8 KB | dawehner |
| #38 | 2874509--interdiff--33-38.txt | 14.58 KB | e0ipso |
| #38 | 2874509--entity-serialization-helper--38.patch | 10.77 KB | e0ipso |
Comments
Comment #2
e0ipsoAwesome! Thanks @DamienMcKenna.
I've been meaning to check if https://www.drupal.org/project/http_client_manager can be helpful in that sort of task. Let me know if you end up trying it :-)
Comment #3
damienmckennaI'd specifically like it to *not* use a HTTP request to generate the data, but that might be a starting point until the codebase is refactored to make this easier to do; there's also some code in #2852272: Make it possible to call jsonapi from within templates (thanks for the tip, gabesullice) which I may steal.. I'll see what I can come up with today.
Comment #4
e0ipsoSorry, didn't mean to derail you. HTTP Client Manager will help you upload those entities to the 3rd party using Guzzle in a managed way. Anyways, this is off topic.
Comment #5
damienmckennaThis steals code from #2852272 to provide a new service for obtaining the JSON representation of an output. I need to do some testing to make sure this works as intended, but it should be almost there.
Comment #7
damienmckennaNew patch on its way.
Comment #8
damienmckennaFixed the tests. Also, note to self, don't do print_r($node, TRUE) in D8 X-)
Comment #9
damienmckennaA minor tweak to make sure that the $json and $raw strings are different.
Comment #10
damienmckennaComment #11
damienmckennaThis turned into a code change rather than just documentation.
Comment #12
damienmckennaFYI the code is basically dawehner's code from #2852272 just relocated and wrapped in a new service.
Comment #13
damienmckennaThis changes from verbose() to htmlOutput(), to aid with debugging.
Comment #14
e0ipsoI think the direction we want to go is by using the serializer.
This should provide an structured array. Use
serializeinstead ofnormalizeto get the JSON string.We still want a nice service that helps with this process and a nice documentation page on how to use it. The aforementioned service will use proper dependency injection (unlike my sample code).
As I mentioned in Slack. In addition to the documentation for the service it would be super nice to have a documentation page on how to do basic data replication using the JSON API module.
Comment #15
e0ipsoThe output of the code above is something like:
(Bear in mind that I have some customizations using the extras module that are being reflected here.)
Comment #16
damienmckennaThanks for the tip, e0psio. Further WIP.
Comment #18
damienmckennaI'm kind of confused as to why the patch would throw "Fatal error: Call to a member function getTypeName() on null" when it runs ->normalize($node, $format, $context), i.e. a node, not a custom data structure?
Comment #19
damienmckennaI went back to earlier code for the main logic as it was actually doing a JSON request. Now, however, it's saying the route can't be found.
Comment #20
damienmckennaComment #22
dpolant commentedHere is an updated version of the patch that uses the normalizer directly instead of simulating a request. All tests are green.
Comment #23
dpolant commentedComment #24
damienmckennaAn interdiff for #22.
Comment #25
wim leerss/JSON/JSON API/
Strange classname?
s/json/api_json/
The current user should be injected.
Comment #26
wim leersAlso, let's justify this very well. If for performance reasons we're avoiding a request, then let's document that.
But why not just wrap a request? KISS first, optimization later — premature optimization is the root of all evil etc :)
Comment #27
wim leersAlso, by using a request, you hit the Dynamic Page Cache, rather than doing the same thing uncached over and over again.
Comment #28
damienmckennaPer today's API-First call, this core bug is relevant: #2613044: Requests are pushed onto the request stack twice, popped once
Comment #29
dawehnerNote: In case we go back to subrequests, you'd have issues with #2613044: Requests are pushed onto the request stack twice, popped once, at least graphql ran into the same issue.
Comment #30
damienmckennaFYI related to the performance concerns, we're using this logic via a queueworker, so performance is not important for our use case.
Comment #31
wim leersComment #32
damienmckennaIMHO we should deal with the performance improvements in a separate issue, but make sure this doesn't open up any other specific problems.
Comment #33
damienmckennaThis fixes #25.1 and #25.3.
Comment #35
wim leers#32++
#33: The test failures show that the expectations were incorrect.
:O WTF? :D
Comment #36
damienmckennaSo yeah, the output is different between the two - the serializeEntity() is returning a nested array representation of the JSON object, the normalizeEntity() is returning a JSON structure with no values for each element.
As for the drupalGet(''), I was getting pretty desperate ;-)
Comment #38
e0ipsoThis is another way to skip wrapping a request.
Comment #39
e0ipsoThis is moving in the same direction that the patch in #33. Instead it uses the top level normalizer to produce valid JSON API outputs.
Comment #40
dawehnerTo be honest I personally dislike this abstract function wrappers to save like 3 lines of code but makes it harder for everyone reading it. Maybe you could move the 3rd parameter calculation into a helper method.
Comment #41
e0ipsoIn fact,
doActionis that method. Would you prefer a different name?@DamienMcKenna @dawehner @Wim Leers I'm leaning towards committing this as is and open follow ups if necessary, before it gets stale.
Any final thoughts before merging?
Comment #42
dawehnerHere is an example of what I meant before ... IMHO there is one less level of indirection going on.
Comment #44
dawehnerA quick reroll.
Comment #45
wim leersRelated: making it easy to create JSON API links: #2878463: [PP-1] Define a JSON API link relation for entities:
Entity::toUrl('jsonapi').Comment #47
e0ipsoThanks all!
Comment #49
a.milkovskyThere is a bug now https://www.drupal.org/project/jsonapi/issues/2925043#comment-12350722.
Comment #50
wim leersComment #51
wim leersThe fears I expressed in #26 came true: #2925043: Server error when using the jsonapi.entity.to_jsonapi service.