question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Invalid or incomplete schema is created when directives are defined and used.

See original GitHub issue

GraphQL Playground as well as GraphQL code generator are throwing the following error:

Uncaught Error: Invalid or incomplete schema, unknown type: DirScalarType. Ensure that a full introspection query is used in order to build a client schema.

Code:

import { GraphQLNonNull, GraphQLScalarType, GraphQLInputField, GraphQLInputObjectType, GraphQLArgument, GraphQLInterfaceType, GraphQLField, GraphQLObjectType } from "graphql";
import { Kind } from "graphql";
import { ApolloServer, gql, SchemaDirectiveVisitor } from "apollo-server-express";
import express from "express";

export const app = express();
class MyDirective extends SchemaDirectiveVisitor {
  visitInputFieldDefinition(field: GraphQLInputField, details: {
    objectType: GraphQLInputObjectType;
  }): GraphQLInputField | void | null {
    this.wrapType(field);
  }

  visitArgumentDefinition(argument: GraphQLArgument, details: {
    field: GraphQLField<any, any>;
    objectType: GraphQLObjectType | GraphQLInterfaceType;
  }): GraphQLArgument | void | null {
    this.wrapType(argument);
  }

  wrapType(field: GraphQLInputField | GraphQLArgument) {
    if (
      field.type instanceof GraphQLNonNull &&
      field.type.ofType instanceof GraphQLScalarType
    ) {
      field.type = new GraphQLNonNull(new Type(field.type.ofType, field.name));
      return;
    }

    if (field.type instanceof GraphQLScalarType) {
      field.type = new Type(field.type, field.name);
      return;
    }
  }
}

class Type extends GraphQLScalarType {
  constructor(type: GraphQLScalarType, name: string) {
    console.log("Directive constructor runs!");

    super({
      name: `DirScalarType`,

      // For more information about GraphQLScalar type (de)serialization,
      // see the graphql-js implementation:
      // https://github.com/graphql/graphql-js/blob/31ae8a8e8312/src/type/definition.js#L425-L446

      // to client
      serialize(value) {
        console.log("Directive runs!");
        return value;
      },

      // by client in variable
      parseValue(value) {
        console.log("Directive runs!");
        return value;
      },

      // by client in parameter
      parseLiteral(ast) {
        console.log("Directive runs!");
        switch (ast.kind) {
          case Kind.STRING:
            return ast.value;
          default: {
            return undefined;
          }
        }
      }
    });
  }
}

// Construct a schema, using GraphQL schema language
const typeDefs = gql`
  # scalar DirScalarType
  directive @dir on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
  input MyType {
    name: String @dir
  }
  type Query {
    hello(name: String @dir): String
  }
`;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: () => "Hello world!"
  }
};

const graphQLServer = new ApolloServer({
  typeDefs,
  resolvers,
  schemaDirectives: { dir: MyDirective }
});


graphQLServer.applyMiddleware({ app });

app.listen(4000).on("listening", () => {
  console.log(`listening on server: http://localhost:4000/graphql`);
});

If a scalar type scalar DirScalarType is added in the schema, the error goes away, but the directive fails to run without error.

package.json:

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "ts-node index.ts",
    "test": "echo \"Error: no test specified\" && exit 1",
    "codegen": "graphql-codegen --config codegen.yml --watch"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@graphql-codegen/cli": "1.12.2",
    "@graphql-codegen/introspection": "1.12.2",
    "@graphql-codegen/typescript": "1.12.2",
    "@graphql-codegen/typescript-document-nodes": "1.12.2",
    "@graphql-codegen/typescript-resolvers": "1.12.2",
    "apollo-server-express": "2.10.1",
    "express": "4.17.1",
    "graphql": "14.6.0",
    "ts-node": "8.6.2",
    "typescript": "3.7.5"
  }
}

The expected behavior.

run npm run codegen without error. run graphql playground without error.

The actual behavior.

Running npm run codegen throws an error complaining that the schema is invalid or incomplete.

Running GraphQL Playground will run with error in DevTools Console and query completion will not work in editor.

A simple, runnable reproduction!

https://github.com/TanaseHagi/apollo-server-issue-3775/

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:5
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
mfellnercommented, May 5, 2020

Related issue here: https://github.com/ardatan/graphql-tools/issues/842 And another one here: https://github.com/ardatan/graphql-tools/issues/789

The consensus appears to be that custom GraphQL scalars should not be used for validation going forward but to use alternative solutions like

What will Apollo’s recommended approach to validation be? I think at least the docs at https://www.apollographql.com/docs/graphql-tools/schema-directives/#enforcing-value-restrictions should be updated to reflect the problems with the suggested solution.

0reactions
glassercommented, May 6, 2021

Right now we are planning to remove support for schemaDirectives in Apollo Server 3, because the project that implements it (graphql-tools) considers it to be a legacy API. Folks who want to use schemaDirectives or its non-legacy replacement schemaTransforms can use @graphql-tools/schema directly to create a schema passed in with new ApolloServer({schema}); issues relating to these options should probably be opened in the graphql-tools repo.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I avoid federation schema mismatch during ...
1 supergraph: Invalid definition for directive "@key": argument "fields" should have type "_FieldSet!" but found type "federation__FieldSet!
Read more >
16.20 - TPT04041 Error: %s: Invalid USING directive: expected ...
The USING directive must be in one of two valid forms... ... Cannot finalize schema definition, status = %s · TPT02236 Error: Cannot...
Read more >
Directives - Lighthouse PHP
Returns an aggregate of a column in a given relationship or model. Requires Laravel 8+. """ directive @aggregate( """ The column to aggregate....
Read more >
Spring Boot GraphQL can't load schema - Stack Overflow
You need to create your own object with properties query, operationName and arg. public class Data { private String query; public String ...
Read more >
graphql-tools/schema
assertResolversPresent( schema , resolverValidationOptions? ): void ... The type definitions are written using Schema Definition Language (SDL).
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found