Automattic / vip-block-data-api

WordPress plugin that provides an API to retrieve Gutenberg content as structured JSON.
http://wpvip.com
GNU General Public License v3.0
103 stars 7 forks source link

Add GraphQL API #51

Closed ingeniumed closed 10 months ago

ingeniumed commented 11 months ago

Description

This PR is meant add a GraphQL API to the Block Data API. It assumes that you have WP-GraphQL installed, and uses a filter to tweak the output of the ContentParser to generate the GraphQL response.

In addition, it uses the wp_unique_id function to generate ids for the blocks so that the blocks can be correlated together. The inner_blocks are therefore able to be flattened entirely, thereby bypassing the nested depth problem in graphQL.

This is in the draft status to get initial feedback, as well as to add some tests and guard rails around the GraphQL API.

graphql-rest-demo

Resolves #49

Steps to Test

alecgeatches commented 11 months ago

@ingeniumed I noticed some errors in a response while testing today. In a post, I have this content:

<!-- wp:paragraph -->
<p>Unnested paragraph.</p>
<!-- /wp:paragraph -->

<!-- wp:columns -->
<div class="wp-block-columns"><!-- wp:column -->
<div class="wp-block-column"><!-- wp:paragraph -->
<p>Column 1</p>
<!-- /wp:paragraph --></div>
<!-- /wp:column -->

<!-- wp:column -->
<div class="wp-block-column"><!-- wp:paragraph -->
<p>Column 2</p>
<!-- /wp:paragraph --></div>
<!-- /wp:column -->

<!-- wp:column -->
<div class="wp-block-column"><!-- wp:paragraph -->
<p>Column 3</p>
<!-- /wp:paragraph --></div>
<!-- /wp:column --></div>
<!-- /wp:columns -->

image


And then I query for the blocks/innerBlocks of that post:

query NewQuery {
  post(id: 419, idType: DATABASE_ID) {
    blocksData {
      blocks {
        attributes {
          name
          value
        }
        id
        name
        innerBlocks {
          attributes {
            name
            value
          }
          id
          name
          parentId
        }
      }
    }
  }
}

The result appears to hold the correct blocks, but also a bunch of Internal server error in an errors array:

Click to expand ```json { "errors": [ { "message": "Internal server error", "extensions": { "category": "internal" }, "locations": [ { "line": 12, "column": 11 } ], "path": [ "post", "blocksData", "blocks", 1, "innerBlocks", 0, "attributes" ] }, { "message": "Internal server error", "extensions": { "category": "internal" }, "locations": [ { "line": 12, "column": 11 } ], "path": [ "post", "blocksData", "blocks", 1, "innerBlocks", 2, "attributes" ] }, { "message": "Internal server error", "extensions": { "category": "internal" }, "locations": [ { "line": 12, "column": 11 } ], "path": [ "post", "blocksData", "blocks", 1, "innerBlocks", 4, "attributes" ] } ], "data": { "post": { "blocksData": { "blocks": [ { "attributes": [ { "name": "content", "value": "Unnested paragraph." }, { "name": "dropCap", "value": "" } ], "id": "1", "name": "core/paragraph", "innerBlocks": null }, { "attributes": [ { "name": "isStackedOnMobile", "value": "1" } ], "id": "2", "name": "core/columns", "innerBlocks": [ { "attributes": null, "id": "3", "name": "core/column", "parentId": "2" }, { "attributes": [ { "name": "content", "value": "Column 1" }, { "name": "dropCap", "value": "" } ], "id": "4", "name": "core/paragraph", "parentId": "3" }, { "attributes": null, "id": "5", "name": "core/column", "parentId": "2" }, { "attributes": [ { "name": "content", "value": "Column 2" }, { "name": "dropCap", "value": "" } ], "id": "6", "name": "core/paragraph", "parentId": "5" }, { "attributes": null, "id": "7", "name": "core/column", "parentId": "2" }, { "attributes": [ { "name": "content", "value": "Column 3" }, { "name": "dropCap", "value": "" } ], "id": "8", "name": "core/paragraph", "parentId": "7" } ] } ] } } }, "extensions": { "debug": [ { "type": "DEBUG_LOGS_INACTIVE", "message": "GraphQL Debug logging is not active. To see debug logs, GRAPHQL_DEBUG must be enabled." } ] } } ```
ingeniumed commented 11 months ago

@alecgeatches So the error itself was due to the fact that we were setting the attributes to an empty object array whenever it was empty. This answer has a good explanation for this, and recommends using ArrayObject instead. I switched that over, and have added an extra check for the attributes to ensure our graphQL code doesn't run if its empty. That should resolve it.

ingeniumed commented 11 months ago

One thing I did btw - I moved the analytics usage code out of the rest API and into the parser itself. This way in case someone tries to call the method directly, instead of going through the rest api they'll still be counted. The same applies for the graphQL code as well.

Happy to revert this, but figured this was a good time to rectify that.

ingeniumed commented 11 months ago

The test I added is now failing because Relay cannot be found since wp_graphQL is not bundled with the plugin when running the tests. Gonna try and fix this so the test can stay

ingeniumed commented 11 months ago

I have made all the changes that are necessary, and there are 2 pending questions that I commented on. So this should be good to review once more

alecgeatches commented 10 months ago

@chriszarate Thanks a ton for your review! I believe I've addressed all of your suggestions above. Please take another look when you have a chance. Thank you!

ingeniumed commented 10 months ago

I'll merge this into our release branch, and we can cut a release later this week via that. Thanks for the amazing feedback @chriszarate, and @smithjw1.