diff --git a/docs/types/interfaces.rst b/docs/types/interfaces.rst index 8c049a24..e8bcf1d1 100644 --- a/docs/types/interfaces.rst +++ b/docs/types/interfaces.rst @@ -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 `_. + +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" + } + } }