Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL third-party schemas not generated properly #5067

Closed
mattstein opened this issue Oct 8, 2019 · 6 comments
Closed

GraphQL third-party schemas not generated properly #5067

mattstein opened this issue Oct 8, 2019 · 6 comments
Assignees
Labels
graphql ⚙️ features related to the GraphQL API

Comments

@mattstein
Copy link
Contributor

mattstein commented Oct 8, 2019

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
@dangayle
Copy link

dangayle commented Oct 8, 2019

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.

@andris-sevcenko andris-sevcenko self-assigned this Oct 8, 2019
@andris-sevcenko andris-sevcenko added the graphql ⚙️ features related to the GraphQL API label Oct 8, 2019
@andris-sevcenko
Copy link
Contributor

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 (f4b60b6), 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.

@andris-sevcenko
Copy link
Contributor

Fixed it better with 80192a5, up to 3rd party plugins to follow suit.

(verbb/super-table#300)

@mattstein
Copy link
Contributor Author

mattstein commented Oct 17, 2019

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 added a commit to verbb/snipcart that referenced this issue Oct 17, 2019
Still not correct though, apparently: craftcms/cms#5067 (comment)
@andris-sevcenko
Copy link
Contributor

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

@mattstein
Copy link
Contributor Author

So close. Thanks @andris-sevcenko!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
graphql ⚙️ features related to the GraphQL API
Projects
None yet
Development

No branches or pull requests

3 participants