Interface types

Interface is an abstract GraphQL type that defines certain set of fields and requires other types implementing it to also define same fields in order for schema to be correct.

Interface example

Consider an application implementing a search function. Search can return items of different type, like Client, Order or Product. For each result it displays a short summary text that is a link leading to a page containing the item’s details.

An Interface can be defined in schema that forces those types to define the summary and url fields:

interface SearchResult {
    summary: String!
    url: String!
}

Type definitions can then be updated to implement this interface:

type Client implements SearchResult {
    first_name: String!
    last_name: String!
    summary: String!
    url: String!
}

type Order implements SearchResult {
    ref: String!
    client: Client!
    summary: String!
    url: String!
}

type Product implements SearchResult {
    name: String!
    sku: String!
    summary: String!
    url: String!
}

GraphQL standard requires that every type implementing the Interface also explicitly defines fields from the interface. This is why the summary and url fields repeat on all types in the example.

Like with the union, the SearchResult interface will also need a special resolver named type resolver. This resolver will we called with an object returned from a field resolver and current context, and should return a string containing the name of a GraphQL type, or None if the received type is incorrect:

def resolve_search_result_type(obj, *_):
    if isinstance(obj, Client):
        return "Client"
    if isinstance(obj, Order):
        return "Order"
    if isinstance(obj, Product):
        return "Product"
    return None

Note

Returning None from this resolver will result in null being returned for this field in your query’s result. If a field is not nullable, this will cause the GraphQL query to error.

Ariadne relies on a dedicated InterfaceType class for binding this function to the Interface in your schema:

from ariadne import InterfaceType

search_result = InterfaceType("SearchResult")

@search_result.type_resolver
def resolve_search_result_type(obj, *_):
    ...

If this function is already defined elsewhere (e.g. 3rd party package), you can instantiate the InterfaceType with it as a second argument:

from ariadne import InterfaceType
from .graphql import resolve_search_result_type

search_result = InterfaceType("SearchResult", resolve_search_result_type)

Lastly, your InterfaceType instance should be passed to make_executable_schema together with other types:

schema = make_executable_schema(type_defs, [query, search_result])

Field resolvers

Ariadne’s InterfaceType instances can optionally be used to set resolvers on implementing types fields.

SearchResult interface from previous section implements two fields: summary and url. If resolver implementation for those fields is same for multiple types implementing the interface, InterfaceType instance can be used to set those resolvers for those fields:

@search_result.field("summary")
def resolve_summary(obj, *_):
    return str(obj)


@search_result.field("url")
def resolve_url(obj, *_):
    return obj.get_absolute_url()

InterfaceType extends the ObjectType, so set_field` and ``set_alias are also available:

search_result.set_field("summary", resolve_summary)
search_result.alias("url", "absolute_url")

Note

InterfaceType assigns the resolver to a field only if that field has no resolver already set. This is different from ObjectType that sets resolvers fields if field already has other resolver set.