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: Plugin added Interfaces don't get their type generators called #5149

Closed
khalwat opened this issue Oct 23, 2019 · 1 comment
Closed

Comments

@khalwat
Copy link
Contributor

khalwat commented Oct 23, 2019

SEOmatic (and Retour) both register GraphQL Interfaces -- which define generators that return objects for GraphQL to use.

The issue is here:

https://github.com/craftcms/cms/blob/develop/src/services/Gql.php#L232

            // Create a pre-built schema if that's what they want.
            $interfaces = [
                EntryInterface::class,
                MatrixBlockInterface::class,
                AssetInterface::class,
                UserInterface::class,
                GlobalSetInterface::class,
                ElementInterface::class,
                CategoryInterface::class,
                TagInterface::class,
            ];
            foreach ($interfaces as $interfaceClass) {
                if (!is_subclass_of($interfaceClass, InterfaceType::class)) {
                    throw new GqlException('Incorrectly defined interface ' . $interfaceClass);
                }
                /** @var GeneratorInterface $typeGeneratorClass */
                $typeGeneratorClass = $interfaceClass::getTypeGenerator();
                foreach ($typeGeneratorClass::generateTypes() as $type) {
                    $schemaConfig['types'][] = $type;
                }
            }

Craft iterates through a hard-coded list of Interfaces, and generates the the types for them... but since plugins are not given a chance to be added to said hard-coded list, they fail.

This is a "soft error" in the GraphQL implementation in Craft, but the Apollo layer added via Gatsby and Gridsome do additional type checking to ensure that the returned data matches a registered type:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var graphql_1 = require("graphql");
function resolveFromParentTypename(parent, schema) {
    var parentTypename = parent['__typename'];
    if (!parentTypename) {
        throw new Error('Did not fetch typename for object, unable to resolve interface.');
    }
    var resolvedType = schema.getType(parentTypename);
    if (!(resolvedType instanceof graphql_1.GraphQLObjectType)) {
        throw new Error('__typename did not match an object type: ' + parentTypename + ' -- ' + JSON.stringify(schema));
    }
    return resolvedType;
}
exports.default = resolveFromParentTypename;
//# sourceMappingURL=resolveFromParentTypename.js.map

...which fails, throwing an error.

I manually added my SeomaticInterface to the hard-coded list above, and everything worked peachy:

Screen Shot 2019-10-23 at 1 28 49 AM

Ref: nystudio107/craft-seomatic#487 (comment)

@andris-sevcenko
Copy link
Contributor

The beer is on me when we next meet, @khalwat.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants