Skip to content

Commit 9efdf4c

Browse files
authored
Merge pull request #771 from jkimbo/update-interface-documentation
Update interface documentation
2 parents 9da46e8 + cc54c76 commit 9efdf4c

File tree

2 files changed

+139
-29
lines changed

2 files changed

+139
-29
lines changed

docs/types/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ Types Reference
88
enums
99
scalars
1010
list-and-nonnull
11+
objecttypes
1112
interfaces
12-
abstracttypes
1313
unions
14-
objecttypes
1514
schema
1615
mutations
16+
abstracttypes

docs/types/interfaces.rst

Lines changed: 137 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,170 @@
11
Interfaces
22
==========
33

4-
An Interface contains the essential fields that will be implemented by
5-
multiple ObjectTypes.
4+
An *Interface* is an abstract type that defines a certain set of fields that a
5+
type must include to implement the interface.
66

7-
The basics:
8-
9-
- Each Interface is a Python class that inherits from ``graphene.Interface``.
10-
- Each attribute of the Interface represents a GraphQL field.
11-
12-
Quick example
13-
-------------
14-
15-
This example model defines a ``Character`` interface with a name. ``Human``
16-
and ``Droid`` are two implementations of that interface.
7+
For example, you can define an Interface ``Character`` that represents any
8+
character in the Star Wars trilogy:
179

1810
.. code:: python
1911
2012
import graphene
2113
2214
class Character(graphene.Interface):
23-
name = graphene.String()
15+
id = graphene.ID(required=True)
16+
name = graphene.String(required=True)
17+
friends = graphene.List(lambda: Character)
18+
19+
20+
Any ObjectType that implements ``Character`` will have these exact fields, with
21+
these arguments and return types.
22+
23+
For example, here are some types that might implement ``Character``:
24+
25+
.. code:: python
2426
25-
# Human is a Character implementation
2627
class Human(graphene.ObjectType):
2728
class Meta:
2829
interfaces = (Character, )
2930
30-
born_in = graphene.String()
31+
starships = graphene.List(Starship)
32+
home_planet = graphene.String()
3133
32-
# Droid is a Character implementation
3334
class Droid(graphene.ObjectType):
3435
class Meta:
3536
interfaces = (Character, )
3637
37-
function = graphene.String()
38+
primary_function = graphene.String()
3839
3940
40-
``name`` is a field on the ``Character`` interface that will also exist on both
41-
the ``Human`` and ``Droid`` ObjectTypes (as those implement the ``Character``
42-
interface). Each ObjectType may define additional fields.
41+
Both of these types have all of the fields from the ``Character`` interface,
42+
but also bring in extra fields, ``home_planet``, ``starships`` and
43+
``primary_function``, that are specific to that particular type of character.
4344

44-
The above types have the following representation in a schema:
45+
The full GraphQL schema defition will look like this:
4546

4647
.. code::
4748
4849
interface Character {
49-
name: String
50+
id: ID!
51+
name: String!
52+
friends: [Character]
53+
}
54+
55+
type Human implements Character {
56+
id: ID!
57+
name: String!
58+
friends: [Character]
59+
starships: [Starship]
60+
homePlanet: String
5061
}
5162
5263
type Droid implements Character {
53-
name: String
54-
function: String
64+
id: ID!
65+
name: String!
66+
friends: [Character]
67+
primaryFunction: String
5568
}
5669
57-
type Human implements Character {
58-
name: String
59-
bornIn: String
70+
Interfaces are useful when you want to return an object or set of objects,
71+
which might be of several different types.
72+
73+
For example, you can define a field ``hero`` that resolves to any
74+
``Character``, depending on the episode, like this:
75+
76+
.. code:: python
77+
78+
class Query(graphene.ObjectType):
79+
hero = graphene.Field(
80+
Character,
81+
required=True,
82+
episode=graphene.Int(required=True)
83+
)
84+
85+
def resolve_hero(_, info, episode):
86+
# Luke is the hero of Episode V
87+
if episode == 5:
88+
return get_human(name='Luke Skywalker')
89+
return get_droid(name='R2-D2')
90+
91+
schema = graphene.Schema(query=Query, types=[Human, Droid])
92+
93+
This allows you to directly query for fields that exist on the Character interface
94+
as well as selecting specific fields on any type that implments the interface
95+
using `inline fragments <https://graphql.org/learn/queries/#inline-fragments>`_.
96+
97+
For example, the following query:
98+
99+
.. code::
100+
101+
query HeroForEpisode($episode: Int!) {
102+
hero(episode: $episode) {
103+
__typename
104+
name
105+
... on Droid {
106+
primaryFunction
107+
}
108+
... on Human {
109+
homePlanet
110+
}
111+
}
112+
}
113+
114+
Will return the following data with variables ``{ "episode": 4 }``:
115+
116+
.. code:: json
117+
118+
{
119+
"data": {
120+
"hero": {
121+
"__typename": "Droid",
122+
"name": "R2-D2",
123+
"primaryFunction": "Astromech"
124+
}
125+
}
126+
}
127+
128+
And different data with the variables ``{ "episode": 5 }``:
129+
130+
.. code:: json
131+
132+
{
133+
"data": {
134+
"hero": {
135+
"__typename": "Human",
136+
"name": "Luke Skywalker",
137+
"homePlanet": "Tatooine"
138+
}
139+
}
60140
}
141+
142+
Resolving data objects to types
143+
-------------------------------
144+
145+
As you build out your schema in Graphene it's common for your resolvers to
146+
return objects that represent the data backing your GraphQL types rather than
147+
instances of the Graphene types (e.g. Django or SQLAlchemy models). This works
148+
well with ``ObjectType`` and ``Scalar`` fields, however when you start using
149+
Interfaces you might come across this error:
150+
151+
.. code::
152+
153+
"Abstract type Character must resolve to an Object type at runtime for field Query.hero ..."
154+
155+
This happens because Graphene doesn't have enough information to convert the
156+
data object into a Graphene type needed to resolve the ``Interface``. To solve
157+
this you can define a ``resolve_type`` class method on the ``Interface`` which
158+
maps a data object to a Graphene type:
159+
160+
.. code:: python
161+
162+
class Character(graphene.Interface):
163+
id = graphene.ID(required=True)
164+
name = graphene.String(required=True)
165+
166+
@classmethod
167+
def resolve_type(cls, instance, info):
168+
if instance.type == 'DROID':
169+
return Droid
170+
return Human

0 commit comments

Comments
 (0)