Interfaces
Interfaces are an abstract type which may be implemented by object types.
An interface has fields, but itβs never instantiated. Instead, objects may implement interfaces, which makes them a member of that interface. Also, fields may return interface types. When this happens, the returned object may be any member of that interface.
For example, let's say a Customer
(interface) can either be an Individual
(object) or a Company
(object). Here's what that might look like in the
GraphQL Schema Definition Language
(SDL):
interface Customer { name: String!}
type Company implements Customer { employees: [Individual!]! name: String!}
type Individual implements Customer { employed_by: Company name: String!}
type Query { customers: [Customer!]!}
Notice that the Customer
interface requires the name: String!
field. Both
Company
and Individual
implement that field so that they can satisfy the
Customer
interface.
When querying, you can select the fields on an interface:
query { customers { name }}
Whether the object is a Company
or an Individual
, it doesnβt matter β you
still get their name. If you want some object-specific fields, you can query
them with an
inline fragment, for
example:
query { customers { name ... on Individual { company { name } } }}
Interfaces are a good choice whenever you have a set of objects that are used interchangeably, and they have several significant fields in common. When they donβt have fields in common, use a Union instead.
Defining interfaces
Interfaces are defined using the @strawberry.interface
decorator:
import strawberry
@strawberry.interfaceclass Customer: name: str
interface Customer { name: String!}
Interface classes should never be instantiated directly.
Implementing interfaces
To define an object type that implements an interface, the type must inherit from the interface:
import strawberry
@strawberry.typeclass Individual(Customer): # additional fields
@strawberry.typeclass Company(Customer): # additional fields
If you add an object type which implements an interface, but that object type doesnβt appear in your schema as a field return type or a union member, then you will need to add that object to the Schema definition directly.
schema = strawberry.Schema(query=Query, types=[Individual, Company])
Interfaces can also implement other interfaces:
import strawberry
@strawberry.interfaceclass Error: message: str
@strawberry.interfaceclass FieldError(Error): message: str field: str
@strawberry.typeclass PasswordTooShort(FieldError): message: str field: str fix: str
interface Error { message: String!}
interface FieldError implements Error { message: String! field: String!}
type PasswordTooShort implements FieldError & Error { message: String! field: String! minLength: Int!}
Implementing fields
Interfaces can provide field implementations as well. For example:
import strawberry
@strawberry.interfaceclass Customer: @strawberry.field def name(self) -> str: return self.name.title()
This resolve method will be called by objects who implement the interface.
Object classes can override the implementation by defining their own name
field:
import strawberry
@strawberry.typeclass Company(Customer): @strawberry.field def name(self) -> str: return f"{self.name} Limited"
Resolving an interface
When a fieldβs return type is an interface, GraphQL needs to know what specific
object type to use for the return value. In the example above, each customer
must be categorized as an Individual
or Company
. To do this you need to
always return an instance of an object type from your resolver:
import strawberry
@strawberry.typeclass Query: @strawberry.field def best_customer(self) -> Customer: return Individual(name="Patrick")