Cms: GraphQL third-party schemas not generated properly

Created on 8 Oct 2019  ·  6Comments  ·  Source: craftcms/cms

Description

When directly querying Craft's GraphQL endpoint, attempting to query plugin-added schemas results in an error:

Schema must contain unique named types but contains multiple types named \"handle_BlockType\". Make sure that resolveType function of abstract type \"handle_FieldSchema\" returns the same type instance as referenced anywhere else within the schema (see http://webonyx.github.io/graphql-php/type-system/#type-registry).

This can be observed in Super Table and Neo. I'll also test ImageOptimize and Retour and update this issue.

You can get around this by doing either of two things:

1. Use any reference to __schema in the body of the query.

So...

{
  entries(section: ["homepage"], limit: 1) {
    ... on homepage_homepage_Entry {
      pageBlocks {
        ... on pageBlocks_serviceSummary_BlockType {
          benefits {
            ... on benefits_BlockType {
              text
            }
          }
        }
      }
    }
  }
}

...would fail while...

{
  entries(section: ["homepage"], limit: 1) {
    ... on homepage_homepage_Entry {
      pageBlocks {
        ... on pageBlocks_serviceSummary_BlockType {
          benefits {
            ... on benefits_BlockType {
              text
            }
          }
        }
      }
    }
  }
  __schema {
    types {
      name
    }
  }
}

...would return the full schema as expected. Or,

2. Patch the GraphQL controller to skip the check for __schema:

diff --git a/src/controllers/GraphqlController.php b/src/controllers/GraphqlController.php
index b6b56db..5d7f0b6 100644
--- a/src/controllers/GraphqlController.php
+++ b/src/controllers/GraphqlController.php
@@ -140,7 +140,7 @@ class GraphqlController extends Controller
         }

         try {
-            $schemaDef = $gqlService->getSchemaDef($schema, StringHelper::contains($query, '__schema'));
+            $schemaDef = $gqlService->getSchemaDef($schema, true);
             $result = GraphQL::executeQuery($schemaDef, $query, null, null, $variables, $operationName)
                 ->toArray(true);
         } catch (\Throwable $e) {

The second method is the only way to avoid further errors working with Gatsby or Gridsome, where it's not always possible to jam __schema into its queries.

Steps to reproduce

  1. Establish a section that includes Matrix or Assets in its field layout (for comparison), and a Super Table or Neo field.
  2. Query that section directly on Craft's GraphQL endpoint using the built-in query explorer, GraphQL playground, Insomnia, etc., being sure to include each field reference.
  3. Observe the debug errors relating only to the third party field types.
  4. Include __schema { types { name } } in the query and try again.
  5. Observe that the response includes all field data as expected.
  6. Remove the extra reference from step 4, then patch the GraphQL controller with $schemaDef = $gqlService->getSchemaDef($schema, true);.
  7. Run the query again and observe that the response includes all field data as expected.

Additional info

  • Craft version: 3.3.7
  • PHP version: 7.3.9
  • Database driver & version: MySQL 5.5.5
graphql

Most helpful comment

Fixed it better with https://github.com/craftcms/cms/commit/80192a55f8f89b129abff2b43d4a0c7d66d60f45, up to 3rd party plugins to follow suit.

(verbb/super-table#300)

All 6 comments

I ended up doing the patch like Matt suggested, worked. I was trying to query Neo fields from Gatsby, and I had all the same errors he mentioned.

That patch will work, but it will also impact the performance of the site, especially as the site grows more complex.

We added a workaround/hack for Matrix (https://github.com/craftcms/cms/commit/f4b60b68694ab928974972c36fba5d147801b221), but that was one day before the conference, so it was really more of a "just get this in because we need something" fix. I'll see if I can add a better fix or maybe I have to just fork the GraphQL library we're using.

Fixed it better with https://github.com/craftcms/cms/commit/80192a55f8f89b129abff2b43d4a0c7d66d60f45, up to 3rd party plugins to follow suit.

(verbb/super-table#300)

Sorry to add noise to this issue @andris-sevcenko, but is there a reason this _doesn't_ work? My field returns a fixed array of scalar values so I don't think I need to get a resolver involved:

public function getContentGqlType()
{
    $typeName = $this->handle.'_SnipcartField';

    $productDetailsType = GqlEntityRegistry::getEntity($typeName)
        ?: GqlEntityRegistry::createEntity($typeName, new ObjectType([
            'name'   => $typeName,
            'fields' => [
                'sku'            => Type::string(),
                'price'          => Type::float(),
                'shippable'      => Type::boolean(),
                'taxable'        => Type::boolean(),
                'weight'         => Type::float(),
                'weightUnit'     => Type::string(),
                'length'         => Type::float(),
                'width'          => Type::float(),
                'height'         => Type::float(),
                'inventory'      => Type::int(),
                'dimensionsUnit' => Type::string(),
            ],
        ]));

    return $productDetailsType;
}

The field _is_ defined and present in the schema; it autocompletes in GraphQL tools and everything. The type is registered with GqlEntityRegistry, and yet still I get this error when I try to perform the query:

Tried to load an unregistered type “productDetails_SnipcartField”. This can indicate both a typo in the query or an issue with the schema used.

If I add a__schema string to the query or patch the GraphQL controller, it works fine.

@mattstein because you also have to register the loader that will load this type:

TypeLoader::registerType($typeName, function () use ($productDetailsType) { return $productDetailsType ;});

Hoping to address this in a commit today by registering the loader behind the scenes when you're creating the type.

So close. Thanks @andris-sevcenko!

Was this page helpful?
0 / 5 - 0 ratings