Update interface documentation

This commit is contained in:
Jonathan Kim 2018-06-16 15:10:32 +01:00
parent c102458808
commit 43e87768d2

View File

@ -1,60 +1,142 @@
Interfaces
==========
An Interface contains the essential fields that will be implemented by
multiple ObjectTypes.
An *Interface* is an abstract type that defines a certain set of fields that a
type must include to implement the interface.
The basics:
- Each Interface is a Python class that inherits from ``graphene.Interface``.
- Each attribute of the Interface represents a GraphQL field.
Quick example
-------------
This example model defines a ``Character`` interface with a name. ``Human``
and ``Droid`` are two implementations of that interface.
For example, you can define an Interface ``Character`` that represents any
character in the Star Wars trilogy:
.. code:: python
import graphene
class Character(graphene.Interface):
name = graphene.String()
id = graphene.ID(required=True)
name = graphene.String(required=True)
friends = graphene.List(lambda: Character)
appears_in = graphene.List(Episode, required=True)
Any ObjectType that implements ``Character`` will have these exact fields, with
these arguments and return types.
For example, here are some types that might implement ``Character``:
.. code:: python
# Human is a Character implementation
class Human(graphene.ObjectType):
class Meta:
interfaces = (Character, )
born_in = graphene.String()
starships = graphene.List(Starship)
home_planet = graphene.String()
# Droid is a Character implementation
class Droid(graphene.ObjectType):
class Meta:
interfaces = (Character, )
function = graphene.String()
primary_function = graphene.String()
``name`` is a field on the ``Character`` interface that will also exist on both
the ``Human`` and ``Droid`` ObjectTypes (as those implement the ``Character``
interface). Each ObjectType may define additional fields.
Both of these types have all of the fields from the ``Character`` interface,
but also bring in extra fields, ``home_planet``, ``starships`` and
``primary_function``, that are specific to that particular type of character.
The above types have the following representation in a schema:
The full GraphQL schema defition will look like this:
.. code::
interface Character {
name: String
}
type Droid implements Character {
name: String
function: String
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
type Human implements Character {
name: String
bornIn: String
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
starships: [Starship]
homePlanet: String
}
type Droid implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
primaryFunction: String
}
Interfaces are useful when you want to return an object or set of objects,
which might be of several different types.
For example, you can define a field ``hero`` that resolves to any
``Character``, depending on the episode, like this:
.. code:: python
class Query(graphene.ObjectType):
hero = graphene.Field(
Character,
required=True,
episode=graphene.Field(Episode, required=True)
)
def resolve_hero(_, info, episode):
# Luke is the hero of Episode V
if episode == 5:
return get_human(name='Luke Skywalker')
return get_droid(name='R2-D2')
This allows you to directly query for fields that exist on the Character interface
as well as selecting specific fields on any type that implments the interface
using `inline fragments <https://graphql.org/learn/queries/#inline-fragments>`_.
For example, the following query:
.. code::
query HeroForEpisode($episode: Episode!) {
hero(episode: $episode) {
__typename
name
... on Droid {
primaryFunction
}
... on Human {
homePlanet
}
}
}
Will return the following data with variables ``{ "episode": 4 }``:
.. code:: json
{
"data": {
"hero": {
"__typename": "Droid",
"name": "R2-D2",
"primaryFunction": "Astromech"
}
}
}
And different data with the variables ``{ "episode": 5 }``:
.. code:: json
{
"data": {
"hero": {
"__typename": "Human",
"name": "Luke Skywalker",
"homePlanet": "Tatooine"
}
}
}