Skip to content

Commit

Permalink
Add skipValidation option. (#839)
Browse files Browse the repository at this point in the history
* Don't validate if query is already an AST.

* Skip validation option.
  • Loading branch information
damour authored and evans committed Jul 13, 2018
1 parent b5039f3 commit 8bcb666
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All of the packages in the `apollo-server` repo are released with the same versi

### vNEXT

* Add skipValidation option [PR #839](https://github.com/apollographql/apollo-server/pull/839)
* `apollo-server-module-graphiql`: adds an option to the constructor to disable url rewriting when editing a query [PR #1047](https://github.com/apollographql/apollo-server/pull/1047)
* Upgrade `subscription-transport-ws` to 0.9.9 for Graphiql

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Apollo Server can be configured with an options object with the following fields
* **context**: the context value passed to resolvers during GraphQL execution
* **rootValue**: the value passed to the first resolve function
* **formatError**: a function to apply to every error before sending the response to clients
* **skipValidation**: skip query validation (increase performance, use carefully, only with whitelisting)
* **validationRules**: additional GraphQL validation rules to be applied to client-specified queries
* **formatParams**: a function applied for each query in a batch to format parameters before execution
* **formatResponse**: a function applied to each response after execution
Expand All @@ -228,6 +229,7 @@ All options except for `schema` are optional.
### Whitelisting

The `formatParams` function can be used in combination with the `OperationStore` to enable whitelisting.
In this case query parsing and validation will be called only once when saving to store.

```js
const store = new OperationStore(Schema);
Expand All @@ -236,6 +238,7 @@ graphqlOptions = {
schema: Schema,
formatParams(params) {
params['query'] = store.get(params.operationName);
params['skipValidation'] = true;
return params;
},
};
Expand Down
25 changes: 14 additions & 11 deletions packages/apollo-server-core/src/runQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface QueryOptions {
debug?: boolean;
tracing?: boolean;
cacheControl?: boolean | CacheControlExtensionOptions;
skipValidation?: boolean;
}

export function runQuery(options: QueryOptions): Promise<GraphQLResponse> {
Expand Down Expand Up @@ -171,17 +172,19 @@ function doRunQuery(options: QueryOptions): Promise<GraphQLResponse> {
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, options.formatError),
});
if (options.skipValidation !== true) {
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, options.formatError),
});
}
}

if (extensionStack) {
Expand Down
33 changes: 33 additions & 0 deletions packages/apollo-server-integration-testsuite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const request = require('supertest');
import { GraphQLOptions } from 'apollo-server-core';
import * as GraphiQL from 'apollo-server-module-graphiql';
import { OperationStore } from 'apollo-server-module-operation-store';
import { LogAction } from '../../apollo-server-core/dist';

const personType = new GraphQLObjectType({
name: 'PersonType',
Expand Down Expand Up @@ -1054,6 +1055,38 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
expect(res.body).to.deep.equal(expected);
});
});

it('do not validate if query is already an AST', async () => {
const store = new OperationStore(schema);
let validationCalled = false;
store.put('query testquery{ testString }');
app = await createApp({
graphqlOptions: {
schema,
formatParams(params) {
params['query'] = store.get(params.operationName);
params['skipValidation'] = true;
return params;
},
logFunction: ({ action }) => {
if (action == LogAction.validation) {
validationCalled = true;
}
},
},
});
const req = request(app)
.post('/graphql')
.send({
operationName: 'testquery',
});
return req.then(res => {
return expect(
validationCalled,
'Validation should not be called if skipValidation option provided',
).to.equal(false);
});
});
});

describe('server setup', () => {
Expand Down

0 comments on commit 8bcb666

Please sign in to comment.