mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 01:47:45 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			436 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			436 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
.. _ObjectType:
 | 
						|
 | 
						|
ObjectType
 | 
						|
==========
 | 
						|
 | 
						|
A Graphene *ObjectType* is the building block used to define the relationship between **Fields** in your **Schema** and how their data is retrieved.
 | 
						|
 | 
						|
The basics:
 | 
						|
 | 
						|
- Each ObjectType is a Python class that inherits from ``graphene.ObjectType``.
 | 
						|
- Each attribute of the ObjectType represents a ``Field``.
 | 
						|
- Each ``Field`` has a :ref:`resolver method<Resolvers>` to fetch data (or :ref:`DefaultResolver`).
 | 
						|
 | 
						|
Quick example
 | 
						|
-------------
 | 
						|
 | 
						|
This example model defines a Person, with a first and a last name:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    class Person(ObjectType):
 | 
						|
        first_name = String()
 | 
						|
        last_name = String()
 | 
						|
        full_name = String()
 | 
						|
 | 
						|
        def resolve_full_name(parent, info):
 | 
						|
            return f"{parent.first_name} {parent.last_name}"
 | 
						|
 | 
						|
This *ObjectType* defines the field **first\_name**, **last\_name**, and **full\_name**. Each field is specified as a class attribute, and each attribute maps to a Field. Data is fetched by our ``resolve_full_name`` :ref:`resolver method<Resolvers>` for ``full_name`` field and the :ref:`DefaultResolver` for other fields.
 | 
						|
 | 
						|
The above ``Person`` ObjectType has the following schema representation:
 | 
						|
 | 
						|
.. code::
 | 
						|
 | 
						|
    type Person {
 | 
						|
      firstName: String
 | 
						|
      lastName: String
 | 
						|
      fullName: String
 | 
						|
    }
 | 
						|
 | 
						|
.. _Resolvers:
 | 
						|
 | 
						|
Resolvers
 | 
						|
---------
 | 
						|
 | 
						|
A **Resolver** is a method that helps us answer **Queries** by fetching data for a **Field** in our **Schema**.
 | 
						|
 | 
						|
Resolvers are lazily executed, so if a field is not included in a query, its resolver will not be executed.
 | 
						|
 | 
						|
Each field on an *ObjectType* in Graphene should have a corresponding resolver method to fetch data. This resolver method should match the field name. For example, in the ``Person`` type above, the ``full_name`` field is resolved by the method ``resolve_full_name``.
 | 
						|
 | 
						|
Each resolver method takes the parameters:
 | 
						|
 | 
						|
* :ref:`ResolverParamParent` for the value object use to resolve most fields
 | 
						|
* :ref:`ResolverParamInfo` for query and schema meta information and per-request context
 | 
						|
* :ref:`ResolverParamGraphQLArguments` as defined on the **Field**.
 | 
						|
 | 
						|
.. _ResolverArguments:
 | 
						|
 | 
						|
Resolver Parameters
 | 
						|
~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
.. _ResolverParamParent:
 | 
						|
 | 
						|
Parent Value Object (*parent*)
 | 
						|
******************************
 | 
						|
 | 
						|
This parameter is typically used to derive the values for most fields on an *ObjectType*.
 | 
						|
 | 
						|
The first parameter of a resolver method (*parent*) is the value object returned from the resolver of the parent field. If there is no parent field, such as a root Query field, then the value for *parent* is set to the ``root_value`` configured while executing the query (default ``None``). See :ref:`SchemaExecute` for more details on executing queries.
 | 
						|
 | 
						|
Resolver example
 | 
						|
^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
If we have a schema with Person type and one field on the root query.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String, Field
 | 
						|
 | 
						|
    def get_human(name):
 | 
						|
        first_name, last_name = name.split()
 | 
						|
        return Person(first_name, last_name)
 | 
						|
 | 
						|
    class Person(ObjectType):
 | 
						|
        full_name = String()
 | 
						|
 | 
						|
        def resolve_full_name(parent, info):
 | 
						|
            return f"{parent.first_name} {parent.last_name}"
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        me = Field(Person)
 | 
						|
 | 
						|
        def resolve_me(parent, info):
 | 
						|
            # returns an object that represents a Person
 | 
						|
            return get_human(name="Luke Skywalker")
 | 
						|
 | 
						|
When we execute a query against that schema.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    schema = Schema(query=Query)
 | 
						|
 | 
						|
    query_string = "{ me { fullName } }"
 | 
						|
    result = schema.execute(query_string)
 | 
						|
 | 
						|
    assert result.data["me"] == {"fullName": "Luke Skywalker"}
 | 
						|
 | 
						|
Then we go through the following steps to resolve this query:
 | 
						|
 | 
						|
* ``parent`` is set with the root_value from query execution (None).
 | 
						|
* ``Query.resolve_me`` called with ``parent`` None which returns a value object ``Person("Luke", "Skywalker")``.
 | 
						|
* This value object is then used as ``parent`` while calling ``Person.resolve_full_name`` to resolve the scalar String value "Luke Skywalker".
 | 
						|
* The scalar value is serialized and sent back in the query response.
 | 
						|
 | 
						|
Each resolver returns the next :ref:`ResolverParamParent` to be used in executing the following resolver in the chain. If the Field is a Scalar type, that value will be serialized and sent in the **Response**. Otherwise, while resolving Compound types like *ObjectType*, the value be passed forward as the next :ref:`ResolverParamParent`.
 | 
						|
 | 
						|
Naming convention
 | 
						|
^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
This :ref:`ResolverParamParent` is sometimes named ``obj``, ``parent``, or ``source`` in other GraphQL documentation. It can also be named after the value object being resolved (ex. ``root`` for a root Query or Mutation, and ``person`` for a Person value object). Sometimes this argument will be named ``self`` in Graphene code, but this can be misleading due to :ref:`ResolverImplicitStaticMethod` while executing queries in Graphene.
 | 
						|
 | 
						|
.. _ResolverParamInfo:
 | 
						|
 | 
						|
GraphQL Execution Info (*info*)
 | 
						|
*******************************
 | 
						|
 | 
						|
The second parameter provides two things:
 | 
						|
 | 
						|
* reference to meta information about the execution of the current GraphQL Query (fields, schema, parsed query, etc.)
 | 
						|
* access to per-request ``context`` which can be used to store user authentication, data loader instances or anything else useful for resolving the query.
 | 
						|
 | 
						|
Only context will be required for most applications. See :ref:`SchemaExecuteContext` for more information about setting context.
 | 
						|
 | 
						|
.. _ResolverParamGraphQLArguments:
 | 
						|
 | 
						|
GraphQL Arguments (*\*\*kwargs*)
 | 
						|
********************************
 | 
						|
 | 
						|
Any arguments that a field defines gets passed to the resolver function as
 | 
						|
keyword arguments. For example:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, Field, String
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        human_by_name = Field(Human, name=String(required=True))
 | 
						|
 | 
						|
        def resolve_human_by_name(parent, info, name):
 | 
						|
            return get_human(name=name)
 | 
						|
 | 
						|
You can then execute the following query:
 | 
						|
 | 
						|
.. code::
 | 
						|
 | 
						|
    query {
 | 
						|
        humanByName(name: "Luke Skywalker") {
 | 
						|
            firstName
 | 
						|
            lastName
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
*Note:* There are several arguments to a field that are "reserved" by Graphene
 | 
						|
(see :ref:`fields-mounted-types`).
 | 
						|
You can still define an argument that clashes with one of these fields by using
 | 
						|
the ``args`` parameter like so:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, Field, String
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        answer = String(args={'description': String()})
 | 
						|
 | 
						|
        def resolve_answer(parent, info, description):
 | 
						|
            return description
 | 
						|
 | 
						|
 | 
						|
Convenience Features of Graphene Resolvers
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
.. _ResolverImplicitStaticMethod:
 | 
						|
 | 
						|
Implicit staticmethod
 | 
						|
*********************
 | 
						|
 | 
						|
One surprising feature of Graphene is that all resolver methods are treated implicitly as staticmethods. This means that, unlike other methods in Python, the first argument of a resolver is *never* ``self`` while it is being executed by Graphene. Instead, the first argument is always :ref:`ResolverParamParent`.  In practice, this is very convenient as, in GraphQL, we are almost always more concerned with the using the parent value object to resolve queries than attributes on the Python object itself.
 | 
						|
 | 
						|
The two resolvers in this example are effectively the same.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    class Person(ObjectType):
 | 
						|
        first_name = String()
 | 
						|
        last_name = String()
 | 
						|
 | 
						|
        @staticmethod
 | 
						|
        def resolve_first_name(parent, info):
 | 
						|
            '''
 | 
						|
            Decorating a Python method with `staticmethod` ensures that `self` will not be provided as an
 | 
						|
            argument. However, Graphene does not need this decorator for this behavior.
 | 
						|
            '''
 | 
						|
            return parent.first_name
 | 
						|
 | 
						|
        def resolve_last_name(parent, info):
 | 
						|
            '''
 | 
						|
            Normally the first argument for this method would be `self`, but Graphene executes this as
 | 
						|
            a staticmethod implicitly.
 | 
						|
            '''
 | 
						|
            return parent.last_name
 | 
						|
 | 
						|
        # ...
 | 
						|
 | 
						|
If you prefer your code to be more explicit, feel free to use ``@staticmethod`` decorators. Otherwise, your code may be cleaner without them!
 | 
						|
 | 
						|
.. _DefaultResolver:
 | 
						|
 | 
						|
Default Resolver
 | 
						|
****************
 | 
						|
 | 
						|
If a resolver method is not defined for a **Field** attribute on our *ObjectType*, Graphene supplies a default resolver.
 | 
						|
 | 
						|
If the :ref:`ResolverParamParent` is a dictionary, the resolver will look for a dictionary key matching the field name. Otherwise, the resolver will get the attribute from the parent value object matching the field name.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from collections import namedtuple
 | 
						|
 | 
						|
    from graphene import ObjectType, String, Field, Schema
 | 
						|
 | 
						|
    PersonValueObject = namedtuple("Person", ["first_name", "last_name"])
 | 
						|
 | 
						|
    class Person(ObjectType):
 | 
						|
        first_name = String()
 | 
						|
        last_name = String()
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        me = Field(Person)
 | 
						|
        my_best_friend = Field(Person)
 | 
						|
 | 
						|
        def resolve_me(parent, info):
 | 
						|
            # always pass an object for `me` field
 | 
						|
            return PersonValueObject(first_name="Luke", last_name="Skywalker")
 | 
						|
 | 
						|
        def resolve_my_best_friend(parent, info):
 | 
						|
            # always pass a dictionary for `my_best_fiend_field`
 | 
						|
            return {"first_name": "R2", "last_name": "D2"}
 | 
						|
 | 
						|
    schema = Schema(query=Query)
 | 
						|
    result = schema.execute('''
 | 
						|
        {
 | 
						|
            me { firstName lastName }
 | 
						|
            myBestFriend { firstName lastName }
 | 
						|
        }
 | 
						|
    ''')
 | 
						|
    # With default resolvers we can resolve attributes from an object..
 | 
						|
    assert result.data["me"] == {"firstName": "Luke", "lastName": "Skywalker"}
 | 
						|
 | 
						|
    # With default resolvers, we can also resolve keys from a dictionary..
 | 
						|
    assert result.data["myBestFriend"] == {"firstName": "R2", "lastName": "D2"}
 | 
						|
 | 
						|
Advanced
 | 
						|
~~~~~~~~
 | 
						|
 | 
						|
GraphQL Argument defaults
 | 
						|
*************************
 | 
						|
 | 
						|
If you define an argument for a field that is not required (and in a query
 | 
						|
execution it is not provided as an argument) it will not be passed to the
 | 
						|
resolver function at all. This is so that the developer can differentiate
 | 
						|
between a ``undefined`` value for an argument and an explicit ``null`` value.
 | 
						|
 | 
						|
For example, given this schema:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        hello = String(required=True, name=String())
 | 
						|
 | 
						|
        def resolve_hello(parent, info, name):
 | 
						|
            return name if name else 'World'
 | 
						|
 | 
						|
And this query:
 | 
						|
 | 
						|
.. code::
 | 
						|
 | 
						|
    query {
 | 
						|
        hello
 | 
						|
    }
 | 
						|
 | 
						|
An error will be thrown:
 | 
						|
 | 
						|
.. code::
 | 
						|
 | 
						|
    TypeError: resolve_hello() missing 1 required positional argument: 'name'
 | 
						|
 | 
						|
You can fix this error in several ways. Either by combining all keyword arguments
 | 
						|
into a dict:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        hello = String(required=True, name=String())
 | 
						|
 | 
						|
        def resolve_hello(parent, info, **kwargs):
 | 
						|
            name = kwargs.get('name', 'World')
 | 
						|
            return f'Hello, {name}!'
 | 
						|
 | 
						|
Or by setting a default value for the keyword argument:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        hello = String(required=True, name=String())
 | 
						|
 | 
						|
        def resolve_hello(parent, info, name='World'):
 | 
						|
            return f'Hello, {name}!'
 | 
						|
 | 
						|
One can also set a default value for an Argument in the GraphQL schema itself using Graphene!
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    class Query(ObjectType):
 | 
						|
        hello = String(
 | 
						|
            required=True,
 | 
						|
            name=String(default_value='World')
 | 
						|
        )
 | 
						|
 | 
						|
        def resolve_hello(parent, info, name):
 | 
						|
            return f'Hello, {name}!'
 | 
						|
 | 
						|
Resolvers outside the class
 | 
						|
***************************
 | 
						|
 | 
						|
A field can use a custom resolver from outside the class:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, String
 | 
						|
 | 
						|
    def resolve_full_name(person, info):
 | 
						|
        return f"{person.first_name} {person.last_name}"
 | 
						|
 | 
						|
    class Person(ObjectType):
 | 
						|
        first_name = String()
 | 
						|
        last_name = String()
 | 
						|
        full_name = String(resolver=resolve_full_name)
 | 
						|
 | 
						|
 | 
						|
Instances as value objects
 | 
						|
**************************
 | 
						|
 | 
						|
Graphene ``ObjectType``\ s can act as value objects too. So with the
 | 
						|
previous example you could use ``Person`` to capture data for each of the *ObjectType*'s fields.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    peter = Person(first_name='Peter', last_name='Griffin')
 | 
						|
 | 
						|
    peter.first_name  # prints "Peter"
 | 
						|
    peter.last_name  # prints "Griffin"
 | 
						|
 | 
						|
Field camelcasing
 | 
						|
*****************
 | 
						|
 | 
						|
Graphene automatically camelcases fields on *ObjectType* from ``field_name`` to ``fieldName`` to conform with GraphQL standards. See :ref:`SchemaAutoCamelCase` for more information.
 | 
						|
 | 
						|
*ObjectType* Configuration - Meta class
 | 
						|
---------------------------------------
 | 
						|
 | 
						|
Graphene uses a Meta inner class on *ObjectType* to set different options.
 | 
						|
 | 
						|
GraphQL type name
 | 
						|
~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
By default the type name in the GraphQL schema will be the same as the class name
 | 
						|
that defines the ``ObjectType``. This can be changed by setting the ``name``
 | 
						|
property on the ``Meta`` class:
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType
 | 
						|
 | 
						|
    class MyGraphQlSong(ObjectType):
 | 
						|
        class Meta:
 | 
						|
            name = 'Song'
 | 
						|
 | 
						|
GraphQL Description
 | 
						|
~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
The schema description of an *ObjectType* can be set as a docstring on the Python object or on the Meta inner class.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType
 | 
						|
 | 
						|
    class MyGraphQlSong(ObjectType):
 | 
						|
        ''' We can set the schema description for an Object Type here on a docstring '''
 | 
						|
        class Meta:
 | 
						|
            description = 'But if we set the description in Meta, this value is used instead'
 | 
						|
 | 
						|
Interfaces & Possible Types
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Setting ``interfaces`` in Meta inner class specifies the GraphQL Interfaces that this Object implements.
 | 
						|
 | 
						|
Providing ``possible_types`` helps Graphene resolve ambiguous types such as interfaces or Unions.
 | 
						|
 | 
						|
See :ref:`Interfaces` for more information.
 | 
						|
 | 
						|
.. code:: python
 | 
						|
 | 
						|
    from graphene import ObjectType, Node
 | 
						|
 | 
						|
    Song = namedtuple('Song', ('title', 'artist'))
 | 
						|
 | 
						|
    class MyGraphQlSong(ObjectType):
 | 
						|
        class Meta:
 | 
						|
            interfaces = (Node, )
 | 
						|
            possible_types = (Song, )
 | 
						|
 | 
						|
.. _Interface: /docs/interfaces/
 |