graphql-tools: introspectSchema throw when underlying schema have contraint directives

/label bug

I’m trying to make schema stitching with underlying schemas having GraphQL contraint directives.

But the stitching process is throwing an error on introspectSchema:

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

    at getNamedType (/Users/yves/repo/node_modules/graphql/utilities/buildClientSchema.js:96:13)
    at getType (/Users/yves/repo/node_modules/graphql/utilities/buildClientSchema.js:87:12)
    at getInputType (/Users/yves/repo/node_modules/graphql/utilities/buildClientSchema.js:104:16)
    at buildInputValue (/Users/yves/repo/node_modules/graphql/utilities/buildClientSchema.js:249:16)
    at /Users/yves/repo/node_modules/graphql/jsutils/keyValMap.js:28:31
    at Array.reduce (<anonymous>)
    at keyValMap (/Users/yves/repo/node_modules/graphql/jsutils/keyValMap.js:27:15)
    at buildInputValueDefMap (/Users/yves/repo/node_modules/graphql/utilities/buildClientSchema.js:243:36)
    at fields (/Users/yves/repo/node_modules/graphql/utilities/buildClientSchema.js:218:16)
    at resolveThunk (/Users/yves/repo/node_modules/graphql/type/definition.js:370:40)

My underlying schema looks like that:

input AddItemInput {
  name: String! @constraint(minLength: 2, maxLength: 40)
}
import ConstraintDirective from "graphql-constraint-directive";

export default makeExecutableSchema({
  typeDefs,
  resolvers,
  schemaDirectives : { constraint: ConstraintDirective }
});

Edit: Related to https://github.com/confuser/graphql-constraint-directive/issues/2

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 4
  • Comments: 22

Commits related to this issue

Most upvoted comments

Same problem. When I tried to define new type in directive for field I get the same error.

My definition:

visitFieldDefinition(field) {
    field.type = new GraphQLObjectType({
      name: 'TestType',
      fields: {
        test: GraphQLString,
      },
    });
  }

Error on introspection:

buildClientSchema.js:102 Uncaught Error: Invalid or incomplete schema, unknown type: TestType. Ensure that a full introspection query is used in order to build a client schema.
    at n (buildClientSchema.js:102)
    at t (buildClientSchema.js:93)
    at i (buildClientSchema.js:116)
    at buildClientSchema.js:237
    at keyValMap.js:28
    at Array.reduce (<anonymous>)
    at r (keyValMap.js:27)
    at S (buildClientSchema.js:231)
    at fields (buildClientSchema.js:180)
    at E (definition.js:168)

@rainum your issue is unrelated IMO. You need to add this to your SDL:

directive @constraint(
    # String constraints
    minLength: Int
    maxLength: Int
    startsWith: String
    endsWith: String
    notContains: String
    pattern: String
    format: String

    # Number constraints
    min: Int
    max: Int
    exclusiveMin: Int
    exclusiveMax: Int
    multipleOf: Int
) on INPUT_FIELD_DEFINITION

As soon as you add it you’ll get the error from above.

Thanks @yaacovCR I’ve released v2 of graphql-constraint-directive which appears to be working well with v6

@mfellner , see below

We use the same approach as in the Apollo docs (https://www.apollographql.com/docs/graphql-tools/schema-directives/#enforcing-value-restrictions) to enforce a restriction on fields that have been annotated with a custom directive.

Hopefully that will work then, as we currently include tests that – in theory – should guarantee support.

Even with unique names for each instance of the custom scalar type we’re seeing the Invalid or incomplete schema error in GraphQL playground. Is there any known workaround?

I noticed that the error disappears if we declare the name(s) of the custom scalars with scalar MyScalarType in the SDL.

The tests above assume the directive names are declared. This is annoying, see #1022, and comment above for thoughts about potentials for workarounds.

However in that case the custom scalar type’s serialize and parse methods are never called and the implementation no longer works.

It should work. If you believe you are following the pattern in the documented example and associated linked test above, you should open a new issue as bug report with a minimal reproduction. I would suggest starting from the code within the test, and the creation of a failing test that mimics your code.

We’d like to enforce restrictions on input type fields based on directive annotations in the SDL so there doesn’t seem to be a different solution than using custom scalar types either?

There is another alternative – checking inputs on field resolution. See end of discussion at #789. Highlights are two relatively recent userland packages, which seems to me to be significant progress and required a great deal of thought and work by their authors:

  1. apollo-validation-directives, by @barbieri
  2. graphql-field-arguments-coercion, by @alexstrat

See, as well, suggestions for changes within the graphql spec referenced by @alexstrat at the end of the README for his project.

I meant unique in the sense that the length constraint is enforced by using a specific type with the appropriate length.

My understand of the issues in #789 relate to the desire to use validation by wrapping arguments rather than by using the serialized and parts functions within a dedicated scalar type. This requires using the directive to simply mark the schema with metadata and an additional function to wrap the required arguments all over the schema according to the metadata.

See #1234 to track potentially new approach to directives, ie functions that take a set of directive names as arguments and return a function that takes a schema that uses those directives in some way as an argument and returns a transformed schema.

There is more context to the above comment that can be found below (doesn’t work): https://github.com/confuser/graphql-constraint-directive/issues/2

There is a hacky workaround suggested there that may not work for everyone.

Any solution or update on this?

I have solved the problem, people.

The high level solution: do not use Prisma and Apollo packages in the same project. They are often incompatible.

What I did:

  • Removed everything Prisma (in my case - graphql-yoga and graphql-import packages).
  • Rewrote schema stitching (removed #import statements and used Apollo’s mergeSchema() JS function).

Now I’m using Apollo Stack v2 (currently RC). It has solved all the problems I had.

I debugged a little. TL;DR: The makeExecutableSchema does not replace the directive object in schema.

  • The graphql-import people tell you to “declare the @constraint scalar in .graphql file”. It effectively creates a directive object in schema. Which is right thing to do IMO. My IDE stops complaining about “undeclared directive!”.
  • The makeExecutableSchema accepts the schemaDirectives and applies the schema visitor to them. But it does not replace the previously declared directive generated by graphql-import.

Here is a screenshot. I made it in node.js debugger one step before exiting the makeExecutableSchema. Basically, that schema variable is what I get. image

As the result, the @constraint directive is not being visited at runtime.

Everything above can be wrong due to my limited understanding.

Same problem here with a similar setup, but error is a bit different:

Error: Directive constraint: Couldn't find type constraint in any of the schemas.
    at collectDirective (/project_dir/node_modules/graphql-import/src/definition.ts:172:15)
    at Array.forEach (<anonymous>)
    at collectNode (/project_dir/node_modules/graphql-import/src/definition.ts:161:21)
    at /project_dir/node_modules/graphql-import/src/definition.ts:135:7
    at Array.forEach (<anonymous>)
    at collectNewTypeDefinitions (/project_dir/node_modules/graphql-import/src/definition.ts:134:26)
    at Object.completeDefinitionPool (/project_dir/node_modules/graphql-import/src/definition.ts:49:39)
    at Object.importSchema (/project_dir/node_modules/graphql-import/src/index.ts:124:26)