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
None
from this resolver will result innull
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")
InterfaceType
assigns the resolver to a field only if that field has no resolver already set. This is different fromObjectType
that sets resolvers fields if field already has other resolver set.