Interface Type Definition

An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.

In graphql-php interface type is an instance of GraphQL\Type\Definition\InterfaceType (or one of it subclasses) which accepts configuration array in constructor:

use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\Type;

$character = new InterfaceType([
    'name' => 'Character',
    'description' => 'A character in the Star Wars Trilogy',
    'fields' => [
        'id' => [
            'type' => Type::nonNull(Type::string()),
            'description' => 'The id of the character.',
        ],
        'name' => [
            'type' => Type::string(),
            'description' => 'The name of the character.'
        ]
    ],
    'resolveType' => function ($value) {
        if ($value->type === 'human') {
            return MyTypes::human();            
        } else {
            return MyTypes::droid();
        }
    }
]);

This example uses inline style for Interface definition, but there are also other styles (using inheritance or composition).

Configuration options

Constructor of InterfaceType accepts an array. Below is a full list of allowed options:

Option Type Notes
name string Required. Unique name of this interface type within Schema
fields array Required. List of fields required to be defined by interface implementors. Same as Fields for Object Type
description string Plain-text description of this type for clients (e.g. used by GraphiQL for auto-generated documentation)
resolveType callback returning instance of ObjectType function($value, $context, GraphQL\Type\Definition\ResolveInfo $info) Any callable that receives $value from resolver of the parent field and returns concrete interface implementor for that $value.

Implementing interface

To implement the Interface simply add it to interfaces array of Object Type definition:

$humanType = new ObjectType([
    'name' => 'Human',
    'fields' => [
        'id' => [
            'type' => Type::nonNull(Type::string()),
            'description' => 'The id of the character.',
        ],
        'name' => [
            'type' => Type::string(),
            'description' => 'The name of the character.'
        ]
    ],
    'interfaces' => [
        $character
    ]
]);

Note that Object Type must include all fields of interface with exact same types (including nonNull specification) and arguments.

The only exception is when object's field type is more specific than the type of this field defined in interface (see Covariant return types for interface fields below)

Covariant return types for interface fields

Object types implementing interface may change field type to more specific. Example:

interface A {
  field1: A
}

type B implements A {
  field1: B
}

Sharing Interface fields

Since every Object Type implementing an Interface must have the same set of fields - it often makes sense to re-use field definitions of Interface in Object Types:

$humanType = new ObjectType([
    'name' => 'Human',
    'interfaces' => [
        $character
    ],
    'fields' => [
        'height' => Type::float(),
        $character->getField('id'),
        $character->getField('name')
    ] 
]);

In this case field definitions are created only once (as a part of Interface Type) and then re-used by all interface implementors. It can save several microseconds and kilobytes + ensures that field definitions of Interface and implementors are always in sync.

Yet it creates a problem with resolution of such fields. There are two ways how shared fields could be resolved:

  1. If field resolution algorithm is the same for all Interface implementors - you can simply add resolve option to field definition in Interface itself.

  2. If field resolution varies from implementor to implementor - you can specify resolveField option in Object Type config and handle field resolutions there (Note: resolve option in field definition has precedence over resolveField option in object type definition)

Interface role in data fetching

The only responsibility of interface in Data Fetching process is to return concrete Object Type for given $value in resolveType. Then resolution of fields is delegated to resolvers of this concrete Object Type.

If resolveType option is omitted, graphql-php will loop through all interface implementors and use their isTypeOf callback to pick the first suitable one. This is obviously less efficient than single resolveType call. So it is recommended to define resolveType whenever possible.