diff --git a/CHANGELOG.md b/CHANGELOG.md index cf178da7cc4..e258faa5b4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### vNEXT * Fix apollo-server-core runQuery breaks async_hooks tracking [PR #733](https://github.com/apollographql/apollo-server/pull/733) +* Don't validate if query is already an AST. [PR #839](https://github.com/apollographql/apollo-server/pull/839) ### v1.3.0 diff --git a/packages/apollo-server-core/src/runHttpQuery.ts b/packages/apollo-server-core/src/runHttpQuery.ts index 780ca7f97c3..c9deba735cb 100644 --- a/packages/apollo-server-core/src/runHttpQuery.ts +++ b/packages/apollo-server-core/src/runHttpQuery.ts @@ -105,8 +105,10 @@ export async function runHttpQuery( const requests: Array = requestPayload.map(requestParams => { try { let query = requestParams.query; + const isQueryString = typeof query === 'string'; + if (isGetRequest) { - if (typeof query === 'string') { + if (isQueryString) { // preparse the query incase of GET so we can assert the operation. query = parse(query); } @@ -149,6 +151,7 @@ export async function runHttpQuery( query: query, variables: variables, context, + isQueryString, rootValue: optionsObject.rootValue, operationName: operationName, logFunction: optionsObject.logFunction, diff --git a/packages/apollo-server-core/src/runQuery.ts b/packages/apollo-server-core/src/runQuery.ts index 5a3e4736999..65b2ba63b1f 100644 --- a/packages/apollo-server-core/src/runQuery.ts +++ b/packages/apollo-server-core/src/runQuery.ts @@ -69,6 +69,7 @@ export interface QueryOptions { debug?: boolean; tracing?: boolean; cacheControl?: boolean; + isQueryString?: boolean; } function runQuery(options: QueryOptions): Promise { @@ -165,15 +166,17 @@ function doRunQuery(options: QueryOptions): Promise { documentAST = options.query as DocumentNode; } - let rules = specifiedRules; - if (options.validationRules) { - rules = rules.concat(options.validationRules); - } - logFunction({ action: LogAction.validation, step: LogStep.start }); - const validationErrors = validate(options.schema, documentAST, rules); - logFunction({ action: LogAction.validation, step: LogStep.end }); - if (validationErrors.length) { - return Promise.resolve({ errors: format(validationErrors) }); + if (options.isQueryString !== false) { + let rules = specifiedRules; + if (options.validationRules) { + rules = rules.concat(options.validationRules); + } + logFunction({ action: LogAction.validation, step: LogStep.start }); + const validationErrors = validate(options.schema, documentAST, rules); + logFunction({ action: LogAction.validation, step: LogStep.end }); + if (validationErrors.length) { + return Promise.resolve({ errors: format(validationErrors) }); + } } if (extensionStack) { diff --git a/packages/apollo-server-express/src/apolloServerHttp.test.ts b/packages/apollo-server-express/src/apolloServerHttp.test.ts index 24c6ac89e4b..56e609c910a 100644 --- a/packages/apollo-server-express/src/apolloServerHttp.test.ts +++ b/packages/apollo-server-express/src/apolloServerHttp.test.ts @@ -37,7 +37,9 @@ import { GraphQLScalarType, GraphQLError, BREAK, + parse, } from 'graphql'; +import { LogAction } from 'apollo-server-core'; const QueryRootType = new GraphQLObjectType({ name: 'QueryRoot', @@ -538,4 +540,40 @@ describe(`GraphQL-HTTP (apolloServer) tests for ${version} express`, () => { }); }); }); + + describe('Query is an AST', () => { + it('Do not validate if query is already an AST.', async () => { + const app = express(); + let validationCalled = false; + + app.use('/graphql', bodyParser.json()); + app.use('/graphql', (req, res, next) => { + req.body.query = parse(req.body.query); + + next(); + }); + app.use( + '/graphql', + graphqlExpress({ + schema: TestSchema, + logFunction: ({ action }) => { + if (action == LogAction.validation) { + validationCalled = true; + } + }, + }), + ); + + const response = await request(app) + .post('/graphql') + .send({ + query: '{ test(who: "World") }', + }); + + expect( + validationCalled, + 'Validation should not be called if query is already an AST', + ).to.equal(false); + }); + }); });