Graphql-code-generator: graphql-codegen fails to load GraphQLSchema

Created on 26 May 2020  Â·  13Comments  Â·  Source: dotansimha/graphql-code-generator

Describe the bug
graphql-codegen fails to load Schema when GraphQLSchema is provided via a custom loader.
However, what is more interesting is, the same configuration may sometimes work, and all seems to be go smooth. But, you will encounter this problem, as you come to it in a later time.

The error is reproducable, and I have provided a log of the error in error.log file. Please refer to the repository.

To Reproduce
Please Refer: https://gitlab.com/errors1/codegen-err
It is easily reproducable by executing npm run cgn on the given repository.

  1. My GraphQL schema:
// Just for the purpose of providing root type Query
import gql from "graphql-tag";

export const gqlTypeDefs = gql`
  type Query{
    user: User!
  }

  type User {
    id: ID
    name: EmailAddress!
    email: String!
  } 
`;
  • It works when you change the type EmailAddress above, and remove 'test.js' from the codegen.yml
  1. My GraphQL operations:

N/A

  1. My codegen.yml config file:
overwrite: true
schema: 
- "test.js"
- "sample_schema.ts"
documents: null
generates:
  tsdefs.ts:
    plugins:
      - "typescript"
      - "typescript-resolvers"
  ./graphql.schema.json:
    plugins:
      - "introspection"
  1. My Custom Loader
const {typeDefs} = require("graphql-scalars");
const {makeExecutableSchema} = require("graphql-tools");

const schema = makeExecutableSchema({typeDefs});
console.log(schema);

module.exports = schema;

Expected behavior
The GraphQLSchema should work as a Schema Type as described in the docs.

Environment:

  • OS: Windows 10 Ver. 1809
  • @graphql-codegen/...: 1.14.0
  • NodeJS: 10.16.0 && 12.16.3

Additional context
I tried reducing the typeDefs array returned by 'graphql-scalars' into a single string, and converting it to GraphQLSchema, it worked for a while. But, the error began to pop up again.

If you can't find the error after a while, try changing relaunching the shell, or your dev enviornment. The errors pops up again.

Solution I am using right now.
// custom loader
let {typeDefs} = require("graphql-scalars");
typeDefs = typeDefs.reduce((a, c) => a+c+' ', '');
module.exports = typeDefs;

Here, the type exported is string instead of GraphQLSchema, whereas GraphQLSchema work.

bug core dependencies

Most helpful comment

@dotansimha We have noPluck option for @graphql-tools/code-file-loader, so you can skip Tag Pluck and use require directly.
https://github.com/ardatan/graphql-tools/blob/master/packages/loaders/code-file/src/index.ts#L111

All 13 comments

@pavittarx I tried your reproduction, and I noticed this:

  • The test.js is not exporting an executable schema - it just exports types. So if your config file points only to it, you'll get:
  ✖ ./graphql.schema.json
    Error: Query root type must be provided.
        at assertValidSchema (/Users/dotansimha/Dev/temp/codegen-err/node_modules/graphql/type/validate.js:71:11)
        at assertValidExecutionArguments (/Users/dotansimha/Dev/temp/codegen-err/node_modules/graphql/execution/execute.js:136:35)
        at executeImpl (/Users/dotansimha/Dev/temp/codegen-err/node_modules/graphql/execution/execute.js:84:3)
        at execute (/Users/dotansimha/Dev/temp/codegen-err/node_modules/graphql/execution/execute.js:62:35)
  • If you export typeDefs from sample_schema - it will work, but if you are trying to export GraphQLSchema from that file, it will fail - because it tries to compile the schema within your file, without the types from test.js so it will fail.

You configuration should include a single schema loader file, that loads the types from graphql-scalars, and builds the schema with those types and your custom types as GraphQLSchema object. If you export a GraphQLSchema object - it should contains everything and should be executable.

If you wish to expose typeDefs and let codegen merge and make your schema executable, you can do it with the same configuration you have in this reproduction.

I noticed a bug with the graphql-tools loaders, I guess we should allow telling the loaders that you prefer to use require over AST lookup, we'll try to fix that.

@dotansimha We have noPluck option for @graphql-tools/code-file-loader, so you can skip Tag Pluck and use require directly.
https://github.com/ardatan/graphql-tools/blob/master/packages/loaders/code-file/src/index.ts#L111

You are right @ardatan :) @pavittarx your custom loader file should look like that:

const { makeExecutableSchema } = require("graphql-tools");
const { typeDefs: scalarsTypeDefs } = require("graphql-scalars");
const gql = require('graphql-tag');

const gqlTypeDefs = gql`
  ${scalarsTypeDefs}

  type Query{
    user: User!
  }

  type User {
    id: ID
    name: EmailAddress!
    email: String!
  }
`;

module.exports = makeExecutableSchema({ typeDefs: gqlTypeDefs });

And the codegen config file:

schema: 
  - ./sample_schema.js:
      noPluck: true
generates:
  tsdefs.ts:
    plugins:
      - "typescript"
      - "typescript-resolvers"
  ./graphql.schema.json:
    plugins:
      - "introspection"

I'll update the docs now!

Is there an equivalent fix to having string interpolation within a one of the documents files? I am currently getting the following error message:

    GraphQLError: Syntax Error: Expected "$", found ")".
        at syntaxError (/Users/alex/git/my-app/node_modules/graphql/error/syntaxError.js:15:10)
        at Parser.expectToken (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:1423:40)
        at Parser.parseVariable (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:249:10)
        at Parser.parseVariableDefinition (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:235:22)
        at Parser.optionalMany (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:1516:28)
        at Parser.parseVariableDefinitions (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:224:17)
        at Parser.parseOperationDefinition (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:191:33)
        at Parser.parseDefinition (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:131:23)
        at Parser.many (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:1537:26)
        at Parser.parseDocument (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:109:25)
        at Object.parse (/Users/alex/git/my-app/node_modules/graphql/language/parser.js:36:17)
        at Object.parseGraphQLSDL (/Users/alex/git/my-app/node_modules/@graphql-tools/utils/index.cjs.js:650:32)
        at parseSDL (/Users/alex/git/my-app/node_modules/@graphql-tools/code-file-loader/index.cjs.js:283:18)
        at CodeFileLoader.load (/Users/alex/git/my-app/node_modules/@graphql-tools/code-file-loader/index.cjs.js:217:28)
        at async loadFile (/Users/alex/git/my-app/node_modules/@graphql-tools/load/index.cjs.js:48:24)
        at async /Users/alex/git/my-app/node_modules/@graphql-tools/load/index.cjs.js:425:24

My code looks like this (I have also tried using the string interpolation function):

      const myMutation = gql(`
          mutation MyMutation( ${params.join(', ')} ) {
            ${aliases}
          }
        `)

@cancan101 you can use custom document loader, and use require in your custom loader to load it from your code file. This way you'll get the interpolated version of the documents and feed it to codegen.
See: https://graphql-code-generator.com/docs/getting-started/documents-field#custom-document-loader

I tried with this in yml + added a loader and don't see the custom loader being used:

schema:
  - "schema.graphql"
documents:
  - "./src/**/*.{ts,tsx}":
    loader: "my-documents-loader.js"

@cancan101 can you please try like that? (YAML is very sensitive when it comes to indentation)

schema:
  - "schema.graphql"
documents:
  - "./src/**/*.{ts,tsx}":
      loader: "my-documents-loader.js"

Ah okay, that fixed the issue with using the loader; however, I am getting the following error using the example loader from the linked docs:

    GraphQLError: Syntax Error: Unexpected Name "import".

You need to add ts-node as well :) because NodeJS itself doesn't know how to load TS files.

Sure, that makes sense (and this is likely due to my ignorance) but after installing ts-node, how do I get the generate script to run / load using it?

Sure, that makes sense (and this is likely due to my ignorance) but after installing ts-node, how do I get the generate script to run / load using it?

You need to specify require config key, see: https://graphql-code-generator.com/docs/getting-started/require-field#typescript-support

Still not quite working. A couple questions:

  1. Should I be able to use the example document loader linked here:? https://graphql-code-generator.com/docs/getting-started/documents-field
  2. Does the require key need to be set under documents or globally in the yml file? I have:
overwrite: true
schema:
  - "schema.graphql"
documents:
  - "./src/**/*.{ts,tsx}":
      loader: "./my-documents-loader.js"

generates:
  src/generated/graphql.tsx:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"
    config:
      skipTypename: true
      withHooks: false
      withHOC: false
      withComponent: false
      withMutationFn: false
      namingConvention:
        enumValues: keep
  ./graphql.schema.json:
    plugins:
      - "introspection"

require:
  - ts-node/register

Error I am getting:

      ✖ Load GraphQL documents
        → Syntax Error: Unexpected Name "import".

Could you create a reproduction on CodeSandbox so we can help you better?

Was this page helpful?
0 / 5 - 0 ratings