From c837e0968e8e98f1461cec47e4e48ede020a766c Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Fri, 27 Nov 2020 15:49:16 +0000 Subject: [PATCH] fix(graphql): ensure buildSchema fails on invalid GraphQL schema (#695) --- .../graphile-build/__tests__/invalid.test.js | 41 +++++++++++++++++++ packages/graphile-build/src/SchemaBuilder.js | 10 ++++- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 packages/graphile-build/__tests__/invalid.test.js diff --git a/packages/graphile-build/__tests__/invalid.test.js b/packages/graphile-build/__tests__/invalid.test.js new file mode 100644 index 000000000..7edfdaf14 --- /dev/null +++ b/packages/graphile-build/__tests__/invalid.test.js @@ -0,0 +1,41 @@ +const { buildSchema, defaultPlugins } = require("../"); + +const InvalidSchemaPlugin = builder => { + builder.hook("GraphQLObjectType:fields", (fields, build, context) => { + if (!context.scope.isRootQuery) { + return fields; + } + return build.extend(fields, { + invalidField: { + type: build.graphql.GraphQLInt, + args: { + invalidArgument: { + // Output types cannot be used as argument types + type: new build.graphql.GraphQLObjectType({ + name: "OutputType", + fields: { + anything: { + type: build.graphql.GraphQLInt, + }, + }, + }), + }, + }, + }, + }); + }); +}; + +test("throws error on invalid schema", async () => { + let error; + try { + await buildSchema([...defaultPlugins, InvalidSchemaPlugin]); + } catch (err) { + error = err; + } + expect(error).toBeTruthy(); + expect(error).toMatchInlineSnapshot(` + [Error: GraphQL schema is invalid: + - The type of Query.invalidField(invalidArgument:) must be Input Type but got: OutputType.] + `); +}); diff --git a/packages/graphile-build/src/SchemaBuilder.js b/packages/graphile-build/src/SchemaBuilder.js index 0bc9515b4..748d2f0dd 100644 --- a/packages/graphile-build/src/SchemaBuilder.js +++ b/packages/graphile-build/src/SchemaBuilder.js @@ -488,13 +488,21 @@ class SchemaBuilder extends EventEmitter { isSchema: true, } ); - this._generatedSchema = this.applyHooks( + const hookedSchema = this.applyHooks( build, "finalize", schema, {}, "Finalising GraphQL schema" ); + const errors = build.graphql.validateSchema(hookedSchema); + if (errors && errors.length) { + throw new Error( + "GraphQL schema is invalid:\n" + + errors.map(e => `- ` + e.message.replace(/\n/g, "\n ")).join("\n") + ); + } + this._generatedSchema = hookedSchema; } if (!this._generatedSchema) { throw new Error("Schema generation failed");