From e27be1e31883c4a711206b1e7d1f179be3bbcc17 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 24 Nov 2020 12:18:38 -0500 Subject: [PATCH] Require opting into SchemaLink validation. Follow-up to #7094, to avoid enabling validation by default, since @apollo/client@3.3.0 is not a major release. --- CHANGELOG.md | 2 +- src/link/schema/__tests__/schemaLink.ts | 26 +++++++++++++++---------- src/link/schema/index.ts | 16 ++++++++++++--- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d3eec8749c..86b5336554e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,7 +75,7 @@ - In addition to the `result.data` property, `useQuery` and `useLazyQuery` will now provide a `result.previousData` property, which can be useful when a network request is pending and `result.data` is undefined, since `result.previousData` can be rendered instead of rendering an empty/loading state.
[@hwillson](https://github.com/hwillson) in [#7082](https://github.com/apollographql/apollo-client/pull/7082) -- The schema link package (`@apollo/client/link/schema`) will now validate incoming queries against its client-side schema, and return `errors` as a GraphQL server would.
+- Passing `validate: true` to the `SchemaLink` constructor will enable validation of incoming queries against the local schema before execution, returning validation errors in `result.errors`, just like a non-local GraphQL endpoint typically would.
[@amannn](https://github.com/amannn) in [#7094](https://github.com/apollographql/apollo-client/pull/7094) - Allow optional arguments in `keyArgs: [...]` arrays for `InMemoryCache` field policies.
diff --git a/src/link/schema/__tests__/schemaLink.ts b/src/link/schema/__tests__/schemaLink.ts index 79da8ee02e4..0e6329ac49e 100644 --- a/src/link/schema/__tests__/schemaLink.ts +++ b/src/link/schema/__tests__/schemaLink.ts @@ -65,17 +65,19 @@ describe('SchemaLink', () => { }); it('calls error when fetch fails', done => { - const schema = makeExecutableSchema({ - typeDefs, - resolvers: { - Query: { - sampleQuery() { - throw new Error('Unauthorized'); + const link = new SchemaLink({ + validate: true, + schema: makeExecutableSchema({ + typeDefs, + resolvers: { + Query: { + sampleQuery() { + throw new Error('Unauthorized'); + } } } - } + }), }); - const link = new SchemaLink({ schema }); const observable = execute(link, { query: sampleQuery, }); @@ -199,8 +201,12 @@ describe('SchemaLink', () => { }); it('reports errors for unknown queries', done => { - const schema = makeExecutableSchema({typeDefs}) - const link = new SchemaLink({ schema }); + const link = new SchemaLink({ + validate: true, + schema: makeExecutableSchema({ + typeDefs, + }), + }); const observable = execute(link, { query: gql` query { diff --git a/src/link/schema/index.ts b/src/link/schema/index.ts index 7479b128abd..1a8f23837b6 100644 --- a/src/link/schema/index.ts +++ b/src/link/schema/index.ts @@ -24,6 +24,12 @@ export namespace SchemaLink { * A context to provide to resolvers declared within the schema. */ context?: ResolverContext | ResolverContextFunction; + + /** + * Validate incoming queries against the given schema, returning + * validation errors as a GraphQL server would. + */ + validate?: boolean; } } @@ -31,12 +37,14 @@ export class SchemaLink extends ApolloLink { public schema: SchemaLink.Options["schema"]; public rootValue: SchemaLink.Options["rootValue"]; public context: SchemaLink.Options["context"]; + public validate: boolean; constructor(options: SchemaLink.Options) { super(); this.schema = options.schema; this.rootValue = options.rootValue; this.context = options.context; + this.validate = !!options.validate; } public request(operation: Operation): Observable { @@ -48,9 +56,11 @@ export class SchemaLink extends ApolloLink { : this.context ) ).then(context => { - const validationErrors = validate(this.schema, operation.query); - if (validationErrors.length > 0) { - return { errors: validationErrors }; + if (this.validate) { + const validationErrors = validate(this.schema, operation.query); + if (validationErrors.length > 0) { + return { errors: validationErrors }; + } } return execute(