Skip to content

Commit 5a6ab11

Browse files
committed
Experimental: customizable validation
1 parent dd41b83 commit 5a6ab11

File tree

4 files changed

+91
-8
lines changed

4 files changed

+91
-8
lines changed

src/utilities/TypeInfo.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,23 @@ export class TypeInfo {
5353
_fieldDefStack: Array<?GraphQLFieldDefinition>;
5454
_directive: ?GraphQLDirective;
5555
_argument: ?GraphQLArgument;
56+
_getFieldDef: typeof getFieldDef;
5657

57-
constructor(schema: GraphQLSchema) {
58+
constructor(
59+
schema: GraphQLSchema,
60+
// NOTE: this experimental optional second parameter is only needed in order
61+
// to support non-spec-compliant codebases. You should never need to use it.
62+
// It may disappear in the future.
63+
getFieldDefFn?: typeof getFieldDef
64+
) {
5865
this._schema = schema;
5966
this._typeStack = [];
6067
this._parentTypeStack = [];
6168
this._inputTypeStack = [];
6269
this._fieldDefStack = [];
6370
this._directive = null;
6471
this._argument = null;
72+
this._getFieldDef = getFieldDefFn || getFieldDef;
6573
}
6674

6775
getType(): ?GraphQLOutputType {
@@ -114,7 +122,7 @@ export class TypeInfo {
114122
var parentType = this.getParentType();
115123
var fieldDef;
116124
if (parentType) {
117-
fieldDef = getFieldDef(schema, parentType, node);
125+
fieldDef = this._getFieldDef(schema, parentType, node);
118126
}
119127
this._fieldDefStack.push(fieldDef);
120128
this._typeStack.push(fieldDef && fieldDef.type);

src/validation/__tests__/harness.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ var QueryRoot = new GraphQLObjectType({
292292
})
293293
});
294294

295-
var defaultSchema = new GraphQLSchema({
295+
export var testSchema = new GraphQLSchema({
296296
query: QueryRoot,
297297
directives: [
298298
new GraphQLDirective({
@@ -316,11 +316,11 @@ function expectInvalid(schema, rules, queryString, expectedErrors) {
316316
}
317317

318318
export function expectPassesRule(rule, queryString) {
319-
return expectValid(defaultSchema, [ rule ], queryString);
319+
return expectValid(testSchema, [ rule ], queryString);
320320
}
321321

322322
export function expectFailsRule(rule, queryString, errors) {
323-
return expectInvalid(defaultSchema, [ rule ], queryString, errors);
323+
return expectInvalid(testSchema, [ rule ], queryString, errors);
324324
}
325325

326326
export function expectPassesRuleWithSchema(schema, rule, queryString, errors) {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Copyright (c) 2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import { describe, it } from 'mocha';
11+
import { expect } from 'chai';
12+
import { testSchema } from './harness';
13+
import { validate, specifiedRules } from '../';
14+
import { visitUsingRules } from '../validate';
15+
import { parse } from '../../language';
16+
import { TypeInfo } from '../../utilities/TypeInfo';
17+
18+
19+
function expectValid(schema, queryString) {
20+
const errors = validate(schema, parse(queryString));
21+
expect(errors).to.deep.equal([], 'Should validate');
22+
}
23+
24+
describe('Validate: Supports full validation', () => {
25+
26+
it('validates queries', () => {
27+
expectValid(testSchema, `
28+
query {
29+
catOrDog {
30+
... on Cat {
31+
furColor
32+
}
33+
... on Dog {
34+
isHousetrained
35+
}
36+
}
37+
}
38+
`);
39+
});
40+
41+
// NOTE: experimental
42+
it('validates using a custom TypeInfo', () => {
43+
44+
// This TypeInfo will never return a valid field.
45+
const typeInfo = new TypeInfo(testSchema, () => null);
46+
47+
const ast = parse(`
48+
query {
49+
catOrDog {
50+
... on Cat {
51+
furColor
52+
}
53+
... on Dog {
54+
isHousetrained
55+
}
56+
}
57+
}
58+
`);
59+
60+
const errors = visitUsingRules(
61+
testSchema,
62+
typeInfo,
63+
ast,
64+
specifiedRules
65+
);
66+
67+
expect(errors).to.deep.equal([
68+
{ message: 'Cannot query field "catOrDog" on "QueryRoot".' }
69+
]);
70+
});
71+
72+
});

src/validation/validate.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,22 @@ export function validate(
5858
'Schema must be an instance of GraphQLSchema. Also ensure that there are ' +
5959
'not multiple versions of GraphQL installed in your node_modules directory.'
6060
);
61-
return visitUsingRules(schema, ast, rules || specifiedRules);
61+
var typeInfo = new TypeInfo(schema);
62+
return visitUsingRules(schema, typeInfo, ast, rules || specifiedRules);
6263
}
6364

6465
/**
6566
* This uses a specialized visitor which runs multiple visitors in parallel,
6667
* while maintaining the visitor skip and break API.
68+
*
69+
* @internal
6770
*/
68-
function visitUsingRules(
71+
export function visitUsingRules(
6972
schema: GraphQLSchema,
73+
typeInfo: TypeInfo,
7074
documentAST: Document,
7175
rules: Array<any>
7276
): Array<GraphQLError> {
73-
var typeInfo = new TypeInfo(schema);
7477
var context = new ValidationContext(schema, documentAST, typeInfo);
7578
var errors = [];
7679

0 commit comments

Comments
 (0)