Skip to content

Commit

Permalink
Merge pull request #669 from robzhu/master
Browse files Browse the repository at this point in the history
Add resolver validation, check if value is a function
  • Loading branch information
robzhu authored Jan 19, 2017
2 parents 1f93cf4 + 3ac1bc1 commit 5cf4cef
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"dot-location": [2, "property"],
"dot-notation": 0,
"eol-last": 2,
"eqeqeq": 2,
"eqeqeq": ["error", "smart"],
"func-names": 0,
"func-style": 0,
"generator-star-spacing": [2, {"before": true, "after": false}],
Expand Down
43 changes: 43 additions & 0 deletions src/type/__tests__/validation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,49 @@ describe('Type System: Object fields must have output types', () => {
});


describe('Type System: Object fields must have valid resolve values', () => {

function schemaWithObjectWithFieldResolver(resolveValue) {
const BadResolverType = new GraphQLObjectType({
name: 'BadResolver',
fields: {
badField: {
type: GraphQLString,
resolve: resolveValue
}
}
});

return new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
f: { type: BadResolverType }
}
})
});
}

it('accepts a lambda as an Object field resolver', () => {
expect(() => schemaWithObjectWithFieldResolver(() => ({}))).not.to.throw();
});

it('rejects an empty Object field resolver', () => {
expect(() => schemaWithObjectWithFieldResolver({})).to.throw(
'BadResolver.badField field resolver must be a function if provided, ' +
'but got: [object Object].'
);
});

it('rejects a constant scalar value resolver', () => {
expect(() => schemaWithObjectWithFieldResolver(0)).to.throw(
'BadResolver.badField field resolver must be a function if provided, ' +
'but got: 0.'
);
});
});


describe('Type System: Objects can only implement interfaces', () => {

function schemaWithObjectImplementingType(implementedType) {
Expand Down
10 changes: 10 additions & 0 deletions src/type/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ function defineFieldMap<TSource, TContext>(
`${type.name}.${fieldName} field type must be Output Type but ` +
`got: ${String(field.type)}.`
);
invariant(
isValidResolver(field.resolve),
`${type.name}.${fieldName} field resolver must be a function if ` +
`provided, but got: ${String(field.resolve)}.`
);
const argsConfig = fieldConfig.args;
if (!argsConfig) {
field.args = [];
Expand Down Expand Up @@ -540,6 +545,11 @@ function isPlainObj(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj);
}

// If a resolver is defined, it must be a function.
function isValidResolver(resolver: any): boolean {
return (resolver == null || typeof resolver === 'function');
}

export type GraphQLObjectTypeConfig<TSource, TContext> = {
name: string;
interfaces?: Thunk<?Array<GraphQLInterfaceType>>;
Expand Down

0 comments on commit 5cf4cef

Please sign in to comment.