Skip to content

Commit 5cf4cef

Browse files
authored
Merge pull request #669 from robzhu/master
Add resolver validation, check if value is a function
2 parents 1f93cf4 + 3ac1bc1 commit 5cf4cef

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

.eslintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"dot-location": [2, "property"],
7070
"dot-notation": 0,
7171
"eol-last": 2,
72-
"eqeqeq": 2,
72+
"eqeqeq": ["error", "smart"],
7373
"func-names": 0,
7474
"func-style": 0,
7575
"generator-star-spacing": [2, {"before": true, "after": false}],

src/type/__tests__/validation-test.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,49 @@ describe('Type System: Object fields must have output types', () => {
11191119
});
11201120

11211121

1122+
describe('Type System: Object fields must have valid resolve values', () => {
1123+
1124+
function schemaWithObjectWithFieldResolver(resolveValue) {
1125+
const BadResolverType = new GraphQLObjectType({
1126+
name: 'BadResolver',
1127+
fields: {
1128+
badField: {
1129+
type: GraphQLString,
1130+
resolve: resolveValue
1131+
}
1132+
}
1133+
});
1134+
1135+
return new GraphQLSchema({
1136+
query: new GraphQLObjectType({
1137+
name: 'Query',
1138+
fields: {
1139+
f: { type: BadResolverType }
1140+
}
1141+
})
1142+
});
1143+
}
1144+
1145+
it('accepts a lambda as an Object field resolver', () => {
1146+
expect(() => schemaWithObjectWithFieldResolver(() => ({}))).not.to.throw();
1147+
});
1148+
1149+
it('rejects an empty Object field resolver', () => {
1150+
expect(() => schemaWithObjectWithFieldResolver({})).to.throw(
1151+
'BadResolver.badField field resolver must be a function if provided, ' +
1152+
'but got: [object Object].'
1153+
);
1154+
});
1155+
1156+
it('rejects a constant scalar value resolver', () => {
1157+
expect(() => schemaWithObjectWithFieldResolver(0)).to.throw(
1158+
'BadResolver.badField field resolver must be a function if provided, ' +
1159+
'but got: 0.'
1160+
);
1161+
});
1162+
});
1163+
1164+
11221165
describe('Type System: Objects can only implement interfaces', () => {
11231166

11241167
function schemaWithObjectImplementingType(implementedType) {

src/type/definition.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,11 @@ function defineFieldMap<TSource, TContext>(
506506
`${type.name}.${fieldName} field type must be Output Type but ` +
507507
`got: ${String(field.type)}.`
508508
);
509+
invariant(
510+
isValidResolver(field.resolve),
511+
`${type.name}.${fieldName} field resolver must be a function if ` +
512+
`provided, but got: ${String(field.resolve)}.`
513+
);
509514
const argsConfig = fieldConfig.args;
510515
if (!argsConfig) {
511516
field.args = [];
@@ -540,6 +545,11 @@ function isPlainObj(obj) {
540545
return obj && typeof obj === 'object' && !Array.isArray(obj);
541546
}
542547

548+
// If a resolver is defined, it must be a function.
549+
function isValidResolver(resolver: any): boolean {
550+
return (resolver == null || typeof resolver === 'function');
551+
}
552+
543553
export type GraphQLObjectTypeConfig<TSource, TContext> = {
544554
name: string;
545555
interfaces?: Thunk<?Array<GraphQLInterfaceType>>;

0 commit comments

Comments
 (0)