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
Returning
Nonefrom this resolver will result innullbeing 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")
InterfaceTypeassigns the resolver to a field only if that field has no resolver already set. This is different fromObjectTypethat sets resolvers fields if field already has other resolver set.