diff --git a/src/type/__tests__/validation.js b/src/type/__tests__/validation.js index f46da17fd9..fc6aa32003 100644 --- a/src/type/__tests__/validation.js +++ b/src/type/__tests__/validation.js @@ -1463,7 +1463,7 @@ describe('Objects must adhere to Interface they implement', () => { }).not.to.throw(); }); - it('rejects an Object which implements an Interface field along with more arguments', () => { + it('accepts an Object which implements an Interface field along with additional optional arguments', () => { expect(() => { var AnotherInterface = new GraphQLInterfaceType({ name: 'AnotherInterface', @@ -1492,10 +1492,43 @@ describe('Objects must adhere to Interface they implement', () => { } }); + return schemaWithFieldType(AnotherObject); + }).not.to.throw(); + }); + + it('rejects an Object which implements an Interface field along with additional required arguments', () => { + expect(() => { + var AnotherInterface = new GraphQLInterfaceType({ + name: 'AnotherInterface', + resolveType: () => null, + fields: { + field: { + type: GraphQLString, + args: { + input: { type: GraphQLString }, + } + } + } + }); + + var AnotherObject = new GraphQLObjectType({ + name: 'AnotherObject', + interfaces: [ AnotherInterface ], + fields: { + field: { + type: GraphQLString, + args: { + input: { type: GraphQLString }, + anotherInput: { type: new GraphQLNonNull(GraphQLString) }, + } + } + } + }); + return schemaWithFieldType(AnotherObject); }).to.throw( - 'AnotherInterface.field does not define argument "anotherInput" but ' + - 'AnotherObject.field provides it.' + 'AnotherObject.field(anotherInput:) is of required type "String!" but ' + + 'is not also provided by the interface AnotherInterface.field.' ); }); diff --git a/src/type/schema.js b/src/type/schema.js index 565976771d..f1d908f663 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -218,15 +218,18 @@ function assertObjectImplementsInterface( ); }); - // Assert argument set invariance. + // Assert additional arguments must not be required. objectField.args.forEach(objectArg => { var argName = objectArg.name; var ifaceArg = find(ifaceField.args, arg => arg.name === argName); - invariant( - ifaceArg, - `${iface}.${fieldName} does not define argument "${argName}" but ` + - `${object}.${fieldName} provides it.` - ); + if (!ifaceArg) { + invariant( + !(objectArg.type instanceof GraphQLNonNull), + `${object}.${fieldName}(${argName}:) is of required type ` + + `"${objectArg.type}" but is not also provided by the ` + + `interface ${iface}.${fieldName}.` + ); + } }); }); }