Skip to content

Commit

Permalink
Throw an error on asynchronous introspection query behavior. (#1955)
Browse files Browse the repository at this point in the history
We expect introspection queries to behave in an synchronous manner since
they do not have any resolvers which return Promises.  This expectation
seems to also be had by `graphql-js` which utilizes `graphqlSync`, rather
than `graphql` for execution of introspection queries.  In fact, this may be
one of the entire reasons that `graphqlSync` exists: to fulfill a contract
for synchronous execution of server introspection.  The introspection tests
within `graphql-js` seem to support this theory[[0]].

Utilities which wrap GraphQL resolvers should take care to maintain the
execution dynamics of what they are wrapping, or they should avoid wrapping
introspection types entirely by checking the type with the
`isIntrospectionType` predicate function from `graphql/type`[[1]].

[0]: https://github.com/graphql/graphql-js/blob/787422956c9554d12d063a41fe35705335ec6290/src/type/__tests__/introspection-test.js
[1]: https://github.com/graphql/graphql-js/blob/74d1e941/src/type/introspection.js#L484.
Closes: #1935
  • Loading branch information
abernix committed Nov 13, 2018
1 parent 26d6c73 commit c82cdec
Showing 1 changed file with 12 additions and 0 deletions.
12 changes: 12 additions & 0 deletions packages/apollo-server-core/src/utils/schemaHash.ts
Expand Up @@ -5,11 +5,23 @@ import stableStringify from 'json-stable-stringify';
import { GraphQLSchema } from 'graphql/type';
import { createHash } from 'crypto';

const hasOwn = Object.prototype.hasOwnProperty;

export function generateSchemaHash(schema: GraphQLSchema): string {
const introspectionQuery = getIntrospectionQuery();
const documentAST = parse(introspectionQuery);
const result = execute(schema, documentAST) as ExecutionResult;

// If the execution of an introspection query results in a then-able, it
// indicates that one or more of its resolvers is behaving in an asynchronous
// manner. This is not the expected behavior of a introspection query
// which does not have any asynchronous resolvers.
if (hasOwn.call(result, 'then')) {
throw new Error(
'The introspection query is resolving asynchronously; execution of an introspection query is not expected to return a `Promise`.',
);
}

if (!result || !result.data || !result.data.__schema) {
throw new Error('Unable to generate server introspection document.');
}
Expand Down

0 comments on commit c82cdec

Please sign in to comment.