Comments

DamienMcKenna created an issue. See original summary.

e0ipso’s picture

Awesome! 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 :-)

damienmckenna’s picture

I'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.

e0ipso’s picture

Sorry, 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.

damienmckenna’s picture

Status: Active » Needs review
StatusFileSize
new4.59 KB

This 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.

Status: Needs review » Needs work

The last submitted patch, 5: jsonapi-n2874509-5.patch, failed testing.

damienmckenna’s picture

Assigned: Unassigned » damienmckenna

New patch on its way.

damienmckenna’s picture

Status: Needs work » Needs review
StatusFileSize
new4.8 KB
new2.54 KB

Fixed the tests. Also, note to self, don't do print_r($node, TRUE) in D8 X-)

damienmckenna’s picture

StatusFileSize
new1.07 KB
new4.83 KB

A minor tweak to make sure that the $json and $raw strings are different.

damienmckenna’s picture

Assigned: damienmckenna » Unassigned
damienmckenna’s picture

Component: Documentation » Code
Category: Task » Feature request

This turned into a code change rather than just documentation.

damienmckenna’s picture

FYI the code is basically dawehner's code from #2852272 just relocated and wrapped in a new service.

damienmckenna’s picture

StatusFileSize
new4.83 KB
new845 bytes

This changes from verbose() to htmlOutput(), to aid with debugging.

e0ipso’s picture

Status: Needs review » Needs work

I think the direction we want to go is by using the serializer.

\Drupal::service('serializer.normalizer.entity.jsonapi')
  ->normalize(
    Node::load(117),
    'api_json',
    ['account' => \Drupal::currentUser(), 'cacheable_metadata' => new CacheableMetadata()]
  )
  ->rasterizeValue();

This should provide an structured array. Use serialize instead of normalize to 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.

e0ipso’s picture

The output of the code above is something like:

[
     "type" => "articles",
     "id" => "d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1",
     "attributes" => [
       "internalId" => 117,
       "status" => true,
       "title" => "Abico Importunus",
       "created" => "2017-04-29T07:40:12+0200",
       "changed" => "2017-04-30T22:40:41+0200",
       "content" => """
         Abdo autem commoveo esse iusto luptatum quae quidem tincidunt valetudo. Abigo brevitas similis sino valetudo vel. Cui importunus minim neque proprius. Autem iustum jugis. Tum utrum ymo. Blandit eros hos jugis occuro suscipere utinam virtus vulpes. Autem ibidem inhibeo macto minim mos oppeto paratus ut. Abluo damnum luptatum natu nisl nutus pneum praemitto valetudo vulputate.\r\n
         \r\n
         Camur quia tincidunt. Dolor enim persto quia. Defui mauris pneum. Abdo antehabeo cui damnum hos jus pertineo valde. At defui ideo probo singularis uxor.\r\n
         \r\n
         Bene blandit commodo consequat conventio iustum neo sit tation. Humo iustum vicis. Abdo abluo adipiscing conventio damnum immitto modo oppeto saepius vulpes. Commoveo elit interdico letalis mauris odio qui refero vel. Genitus ludus neque vereor.\r\n
         \r\n
         Abico capto commoveo. Et haero ludus paulatim quidne valde. Gravis quia ut. Adipiscing et ibidem pertineo qui turpis. Exerci gilvus meus pagus roto valetudo. At distineo iaceo modo nibh quidne tego vicis zelus. Aptent cogo decet enim nisl odio. Ibidem typicus vel. Bene luctus nutus olim oppeto quadrum si utrum venio.\r\n
         \r\n
         Accumsan facilisis ibidem praemitto. Abbas augue facilisi magna suscipit tincidunt. Ex laoreet luptatum. Antehabeo cui decet feugiat iustum ludus paratus tation. Inhibeo neo qui. Adipiscing autem dolus exputo huic incassum iustum odio venio vulputate. Caecus capto cogo ea eum humo metuo minim valde. Blandit distineo duis ea exputo magna si. Adipiscing neo quae vindico. Bene exerci molior neo quae tamen tum usitas vereor voco.\r\n
         \r\n
         Haero incassum nutus praesent quae singularis te. Accumsan camur enim genitus loquor metuo qui voco. Ideo olim pala sino suscipit tum turpis virtus voco. Laoreet ludus metuo modo nutus oppeto tamen velit.\r\n
         \r\n
         Abigo cogo decet eu luctus mos paulatim proprius scisco velit. Accumsan exerci minim venio. Cogo oppeto pneum sino volutpat. Abluo camur immitto iustum minim patria turpis ymo.\r\n
         \r\n
         Aliquam amet laoreet odio probo secundum verto. Abluo causa consectetuer fere quia ratis vulpes. Illum metuo nimis nutus occuro venio. Ex laoreet macto patria tincidunt utinam velit. Autem typicus veniam. Aliquip camur feugiat letalis premo. Conventio damnum imputo luptatum magna patria ullamcorper vindico zelus. Abico erat lenis lucidus magna pala vel. Erat euismod loquor magna.\r\n
         \r\n
         Esca hos jugis olim quae ut. Humo quibus zelus. Dignissim eum obruo pala ut. Commodo consequat conventio genitus quidem ullamcorper. Duis facilisi haero jugis laoreet refero velit. Amet at feugiat gemino iustum obruo quibus similis tation voco.\r\n
         \r\n
         Accumsan at bene dolus exerci paratus quidem saepius si te. Cogo eros eu exerci lenis tation utinam. Adipiscing eros esse haero lobortis neo saepius vulpes.\r\n
         \r\n
         Abdo capto nunc odio volutpat. At interdico luctus macto pecus saepius utrum. Abico brevitas commoveo distineo jugis odio quis saepius sino. Neo populus vindico. Bene distineo luctus. Esca illum iustum occuro quis. Abico esca ex gravis pertineo typicus.\r\n
         \r\n
         Facilisi vereor verto. Abico decet gilvus iustum jus metuo mos oppeto vel wisi. Commodo damnum zelus. Abico conventio interdico loquor natu si valetudo vel. Minim neo os. Abbas bene lenis modo mos os paratus quibus vicis.\r\n
         \r\n
         """,
       "path" => "/node-117-article",
     ],
     "relationships" => [
       "bundle" => [
         "data" => [
           "type" => "node_type--node_type",
           "id" => "24ca428d-44a1-4a96-a372-95dc3ef8020a",
         ],
         "links" => [
           "self" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/relationships/bundle",
           "related" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/bundle",
         ],
       ],
       "author" => [
         "data" => [
           "type" => "user--user",
           "id" => "ca892ac6-af0b-473f-82ba-7c3924eb06d7",
         ],
         "links" => [
           "self" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/relationships/author",
           "related" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/author",
         ],
       ],
       "image" => [
         "data" => [
           "type" => "file--file",
           "id" => "e8eb2b4f-2d94-4c3e-8cc3-9dca66e7b295",
           "meta" => [
             "alt" => "Duis neque pertineo qui ullamcorper.",
             "title" => "",
             "width" => "422",
             "height" => "494",
           ],
         ],
         "links" => [
           "self" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/relationships/image",
           "related" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/image",
         ],
       ],
       "related" => [
         "data" => [
           [
             "type" => "articles",
             "id" => "8bdde825-6cbb-4d13-a96e-227b748aefb1",
           ],
           [
             "type" => "articles",
             "id" => "4822fb9b-ee05-4d77-93b8-5d4fcb611de0",
           ],
         ],
         "links" => [
           "self" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/relationships/related",
           "related" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1/related",
         ],
       ],
       "tags" => [
         "data" => [],
       ],
     ],
     "links" => [
       "self" => "http://default/my-api/articles/d99f021b-c3c8-41f0-bd8d-c8d02c22e2a1",
     ],
   ]

(Bear in mind that I have some customizations using the extras module that are being reflected here.)

damienmckenna’s picture

Status: Needs work » Needs review
StatusFileSize
new4.21 KB
new5.89 KB

Thanks for the tip, e0psio. Further WIP.

Status: Needs review » Needs work

The last submitted patch, 16: jsonapi-n2874509-16.patch, failed testing.

damienmckenna’s picture

I'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?

damienmckenna’s picture

StatusFileSize
new5.05 KB
new4.3 KB

I 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.

damienmckenna’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 19: jsonapi-n2874509-19.patch, failed testing.

dpolant’s picture

StatusFileSize
new4.96 KB

Here is an updated version of the patch that uses the normalizer directly instead of simulating a request. All tests are green.

dpolant’s picture

Status: Needs work » Needs review
damienmckenna’s picture

StatusFileSize
new7.41 KB

An interdiff for #22.

wim leers’s picture

Status: Needs review » Needs work
  1. +++ b/README.md
    @@ -28,3 +28,15 @@ The list of endpoints then looks like the following:
    +It is also possible to obtain the JSON representation of a supported entity:
    

    s/JSON/JSON API/

  2. +++ b/jsonapi.services.yml
    @@ -106,6 +106,10 @@ services:
    +  jsonapi.entity.to_json:
    +    class: Drupal\jsonapi\ToJson
    
    +++ b/src/ToJson.php
    @@ -0,0 +1,75 @@
    +class ToJson {
    

    Strange classname?

  3. +++ b/src/ToJson.php
    @@ -0,0 +1,75 @@
    +    return $this->serializer->serialize($normalized_entity, 'json');
    

    s/json/api_json/

  4. +++ b/src/ToJson.php
    @@ -0,0 +1,75 @@
    +      ->normalize($entity, 'api_json', ['account' => \Drupal::currentUser(), 'cacheable_metadata' => new CacheableMetadata()])
    

    The current user should be injected.

wim leers’s picture

Also, 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 :)

wim leers’s picture

Also, by using a request, you hit the Dynamic Page Cache, rather than doing the same thing uncached over and over again.

damienmckenna’s picture

dawehner’s picture

Note: 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.

damienmckenna’s picture

FYI related to the performance concerns, we're using this logic via a queueworker, so performance is not important for our use case.

wim leers’s picture

Title: Document how to generate JSON structure for an entity » Provide service to simplify generating a JSON API representation of an entity in PHP code
Issue tags: +DX (Developer Experience)
damienmckenna’s picture

IMHO we should deal with the performance improvements in a separate issue, but make sure this doesn't open up any other specific problems.

damienmckenna’s picture

Status: Needs work » Needs review
StatusFileSize
new4.96 KB
new973 bytes

This fixes #25.1 and #25.3.

Status: Needs review » Needs work

The last submitted patch, 33: jsonapi-n2874509-33.patch, failed testing.

wim leers’s picture

#32++

#33: The test failures show that the expectations were incorrect.

+++ b/tests/src/Functional/JsonApiFunctionalToJsonTest.php
@@ -0,0 +1,51 @@
+    drupal_flush_all_caches();
+    $this->drupalGet('');

:O WTF? :D

damienmckenna’s picture

Status: Needs work » Needs review
StatusFileSize
new4.81 KB
new926 bytes

So 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 ;-)

Status: Needs review » Needs work

The last submitted patch, 36: jsonapi-n2874509-36.patch, failed testing.

e0ipso’s picture

Status: Needs work » Needs review
StatusFileSize
new10.77 KB
new14.58 KB

This is another way to skip wrapping a request.

e0ipso’s picture

This is moving in the same direction that the patch in #33. Instead it uses the top level normalizer to produce valid JSON API outputs.

dawehner’s picture

+++ b/src/EntityToJsonApi.php
@@ -0,0 +1,106 @@
+    return $this->doAction($entity, 'serialize');
...
+    return $this->doAction($entity, 'normalize');

To 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.

e0ipso’s picture

Maybe you could move the 3rd parameter calculation into a helper method.

In fact, doAction is 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?

dawehner’s picture

StatusFileSize
new10.8 KB
new3.02 KB

Here is an example of what I meant before ... IMHO there is one less level of indirection going on.

Status: Needs review » Needs work

The last submitted patch, 42: 2874509-42.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new10.79 KB

A quick reroll.

wim leers’s picture

Related: making it easy to create JSON API links: #2878463: [PP-1] Define a JSON API link relation for entities: Entity::toUrl('jsonapi').

  • e0ipso committed b9d37d2 on 8.x-1.x authored by DamienMcKenna
    feat(Serialization): Ease programmatic serialization (#2874509 by...
e0ipso’s picture

Status: Needs review » Fixed

Thanks all!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

a.milkovsky’s picture

wim leers’s picture

wim leers’s picture