diff --git a/src/type/schema.js b/src/type/schema.js index 1b2ea738d1..6365199a42 100644 --- a/src/type/schema.js +++ b/src/type/schema.js @@ -8,6 +8,7 @@ */ import { + isAbstractType, isObjectType, isInterfaceType, isUnionType, @@ -159,6 +160,8 @@ export class GraphQLSchema { this._implementations[iface.name] = [type]; } }); + } else if (isAbstractType(type) && !this._implementations[type.name]) { + this._implementations[type.name] = []; } }); } diff --git a/src/type/validate.js b/src/type/validate.js index d65b0dc87c..5c4cbf143b 100644 --- a/src/type/validate.js +++ b/src/type/validate.js @@ -257,6 +257,9 @@ function validateTypes(context: SchemaValidationContext): void { } else if (isInterfaceType(type)) { // Ensure fields are valid. validateFields(context, type); + + // Ensure Interfaces include at least 1 concrete type. + validateInterfaces(context, type); } else if (isUnionType(type)) { // Ensure Unions include valid member types. validateUnionMembers(context, type); @@ -355,6 +358,21 @@ function validateObjectInterfaces( }); } +function validateInterfaces( + context: SchemaValidationContext, + iface: GraphQLInterfaceType, +): void { + const possibleTypes = context.schema.getPossibleTypes(iface); + + if (possibleTypes.length === 0) { + context.reportError( + `No concrete types found for Interface type ${iface.name}. ` + + `If only referenced via abstraction, add concrete types to schema.types array`, + iface.astNode, + ); + } +} + function validateObjectImplementsInterface( context: SchemaValidationContext, object: GraphQLObjectType,