From 882d18e245439bd4851673f181d83c03e34785a8 Mon Sep 17 00:00:00 2001 From: Dave A Date: Sat, 25 May 2019 15:45:54 -0400 Subject: [PATCH] document graphene core API --- docs/api/index.rst | 89 ++++++++++++++++--------------- graphene/types/argument.py | 29 ++++++++++ graphene/types/context.py | 19 +++++++ graphene/types/enum.py | 22 ++++++++ graphene/types/field.py | 41 ++++++++++++++ graphene/types/inputfield.py | 36 +++++++++++++ graphene/types/inputobjecttype.py | 24 ++++++++- graphene/types/interface.py | 20 +++++++ graphene/types/json.py | 7 ++- graphene/types/mutation.py | 40 +++++++++++++- graphene/types/objecttype.py | 56 +++++++++++++++++++ graphene/types/structures.py | 14 +++++ graphene/types/union.py | 26 +++++++++ graphene/types/unmountedtype.py | 32 ++++++++--- graphene/types/uuid.py | 5 +- 15 files changed, 408 insertions(+), 52 deletions(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index 86460918..47b8b84f 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -10,80 +10,85 @@ Schema .. Uncomment sections / types as API documentation is fleshed out .. in each class -.. Object types -.. ------------ +Object types +------------ -.. .. autoclass:: graphene.ObjectType +.. autoclass:: graphene.ObjectType -.. .. autoclass:: graphene.InputObjectType +.. autoclass:: graphene.InputObjectType -.. Fields (Mounted Types) -.. ---------------------- +.. autoclass:: graphene.Mutation + :members: -.. .. autoclass:: graphene.Field +Fields (Mounted Types) +---------------------- -.. .. autoclass:: graphene.Argument +.. autoclass:: graphene.Field -.. .. autoclass:: graphene.InputField +.. autoclass:: graphene.Argument -.. GraphQL Scalars -.. --------------- +.. autoclass:: graphene.InputField -.. .. autoclass:: graphene.Int +Fields (Unmounted Types) +------------------------ -.. .. autoclass:: graphene.Float +.. autoclass:: graphene.types.unmountedtype.UnmountedType -.. .. autoclass:: graphene.String +GraphQL Scalars +--------------- -.. .. autoclass:: graphene.Boolean +.. autoclass:: graphene.Int() -.. .. autoclass:: graphene.ID +.. autoclass:: graphene.Float() -.. Graphene Scalars -.. ---------------- +.. autoclass:: graphene.String() -.. .. autoclass:: graphene.Date +.. autoclass:: graphene.Boolean() -.. .. autoclass:: graphene.DateTime +.. autoclass:: graphene.ID() -.. .. autoclass:: graphene.Time +Graphene Scalars +---------------- -.. .. autoclass:: graphene.Decimal +.. autoclass:: graphene.Date() -.. .. autoclass:: graphene.UUID +.. autoclass:: graphene.DateTime() -.. .. autoclass:: graphene.JSONString +.. autoclass:: graphene.Time() -.. Structures -.. ---------- +.. autoclass:: graphene.Decimal() -.. .. autoclass:: graphene.List +.. autoclass:: graphene.UUID() -.. .. autoclass:: graphene.NonNull +.. autoclass:: graphene.JSONString() -.. Enum -.. ---- +Enum +---- -.. .. autoclass:: graphene.Enum +.. autoclass:: graphene.Enum() -.. Type Extension -.. -------------- +Structures +---------- -.. .. autoclass:: graphene.Interface +.. autoclass:: graphene.List -.. .. autoclass:: graphene.Union +.. autoclass:: graphene.NonNull -.. Execution Metadata -.. ------------------ +Type Extension +-------------- -.. .. autoclass:: graphene.ResolveInfo +.. autoclass:: graphene.Interface() -.. .. autoclass:: graphene.Context +.. autoclass:: graphene.Union() -.. Mutation -.. -------- +Execution Metadata +------------------ -.. .. autoclass:: graphene.Mutation +.. autoclass:: graphene.ResolveInfo + +.. autoclass:: graphene.Context + +.. autoclass:: graphql.execution.base.ExecutionResult .. Relay .. ----- diff --git a/graphene/types/argument.py b/graphene/types/argument.py index bf304608..67af1d98 100644 --- a/graphene/types/argument.py +++ b/graphene/types/argument.py @@ -8,6 +8,35 @@ from .utils import get_type class Argument(MountedType): + """ + Makes an Argument available on a Field in the GraphQL schema. + + Arguments will be parsed and provided to resolver methods for fields as keyword arguments. + + All ``arg`` and ``**extra_args`` for a ``graphene.Field`` are implicitly mounted as Argument + using the below parameters. + + .. code:: python + + age = graphene.String( + # Boolean implicitly mounted as Argument + dog_years=graphene.Boolean(description='convert to dog years'), + # Boolean explicitly mounted as Argument + decades=graphene.Argument(graphene.Boolean, default_value=False) + ) + + args: + type (class for a graphene.UnmountedType): must be a class (not an instance) of an + unmounted graphene type (ex. scalar or object) which is used for the type of this + argument in the GraphQL schema. + required (bool). Indicates this argument as not null in the graphql scehma. Same behavior + as graphene.NonNull. Default False. + name (str): the name of the GraphQL argument. Defaults to parameter name. + description (str): the description of the GraphQL argument in the schema. + default_value (Any): The value to be provided if the user does not set this argument in + the operation. + """ + def __init__( self, type, diff --git a/graphene/types/context.py b/graphene/types/context.py index bac2073c..d7be7ac9 100644 --- a/graphene/types/context.py +++ b/graphene/types/context.py @@ -1,4 +1,23 @@ class Context(object): + """ + Context can be used to make a convenient container for attributes to provide + for execution for resolvers of a GraphQL operation like a query. + + .. code:: python + + context = Context(loaders=build_dataloaders(), request=my_web_request) + schema.execute('{ hello(name: "world") }', context=context) + + def resolve_hello(parent, info, name): + info.context.request # value set in Context + info.context.loaders # value set in Context + # ... + + args: + **params (Dict[str, Any]): values to make available on Context instance as attributes. + + """ + def __init__(self, **params): for key, value in params.items(): setattr(self, key, value) diff --git a/graphene/types/enum.py b/graphene/types/enum.py index 7b8e71f5..41888505 100644 --- a/graphene/types/enum.py +++ b/graphene/types/enum.py @@ -67,6 +67,28 @@ class EnumMeta(SubclassWithMeta_Meta): class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)): + """ + Enum type defintion + + Defines a static set of values that can be provided as a Field, Argument or InputField. + + .. code:: python + + class NameFormat(graphene.Enum): + FIRST_LAST = 'first_last' + LAST_FIRST = 'last_first' + + Meta: + enum (optional, Enum): Python enum to use as a base for GraphQL Enum. + + name (optional, str): the name of the GraphQL type (must be unique in schema). Defaults to class + name. + description (optional, str): the description of the GraphQL type in the schema. Defaults to class + docstring. + deprecation_reason (optional, str): Setting this value indicates that the enum is + depreciated and may provide instruction or reason on how for clients to proceed. + """ + @classmethod def __init_subclass_with_meta__(cls, enum=None, _meta=None, **options): if not _meta: diff --git a/graphene/types/field.py b/graphene/types/field.py index a1428632..f9275da0 100644 --- a/graphene/types/field.py +++ b/graphene/types/field.py @@ -19,6 +19,47 @@ def source_resolver(source, root, info, **args): class Field(MountedType): + """ + Makes a field available on an ObjectType in the GraphQL schema. Any type can be mounted as a + Field: + + - Object Type + - Scalar Type + - Enum + - Interface + - Union + + All class attributes of ``graphene.ObjectType`` are implicitly mounted as Field using the below + arguments. + + .. code:: python + + class Person(ObjectType): + first_name = graphene.String(required=True) # implicitly mounted as Field + last_name = graphene.Field(String, description='Surname') # explicitly mounted as Field + + args: + type (class for a graphene.UnmountedType): must be a class (not an instance) of an + unmounted graphene type (ex. scalar or object) which is used for the type of this + field in the GraphQL schema. + args (optional, Dict[str, graphene.Argument]): arguments that can be input to the field. + Prefer to use **extra_args. + resolver (optional, Callable): A function to get the value for a Field from the parent + value object. If not set, the default resolver method for the schema is used. + source (optional, str): attribute name to resolve for this field from the parent value + object. Alternative to resolver (cannot set both source and resolver). + deprecation_reason (optional, str): Setting this value indicates that the field is + depreciated and may provide instruction or reason on how for clients to proceed. + required (optional, bool). Indicates this field as not null in the graphql scehma. Same behavior as + graphene.NonNull. Default False. + name (optional, str): the name of the GraphQL field (must be unique in a type). Defaults to attribute + name. + description (optional, str): the description of the GraphQL field in the schema. + default_value (optional, Any): Default value to resolve if none set from schema. + **extra_args (optional, Dict[str, Union[graphene.Argument, graphene.UnmountedType]): any + additional arguments to mount on the field. + """ + def __init__( self, type, diff --git a/graphene/types/inputfield.py b/graphene/types/inputfield.py index cdfea114..43405b4b 100644 --- a/graphene/types/inputfield.py +++ b/graphene/types/inputfield.py @@ -4,6 +4,42 @@ from .utils import get_type class InputField(MountedType): + """ + Makes a field available on an ObjectType in the GraphQL schema. Any type can be mounted as a + Input Field except Interface and Union: + + - Object Type + - Scalar Type + - Enum + + Input object types also can't have arguments on their input fields, unlike regular ``graphene.Field``. + + All class attributes of ``graphene.InputObjectType`` are implicitly mounted as InputField + using the below arguments. + + .. code:: python + + class Person(graphene.InputObjectType): + first_name = graphene.String(required=True) # implicitly mounted as Input Field + last_name = graphene.InputField(String, description='Surname') # explicitly mounted as Input Field + + args: + type (class for a graphene.UnmountedType): must be a class (not an instance) of an + unmounted graphene type (ex. scalar or object) which is used for the type of this + field in the GraphQL schema. + name (optional, str): the name of the GraphQL input field (must be unique in a type). + Defaults to attribute name. + default_value (optional, Any): Default value to use as input if none set in user operation ( + query, mutation, etc.). + deprecation_reason (optional, str): Setting this value indicates that the field is + depreciated and may provide instruction or reason on how for clients to proceed. + description (optional, str): the description of the GraphQL field in the schema. + required (optional, bool). Indicates this input field as not null in the graphql scehma. + Raises a validation error if argument not provided. Same behavior as graphene.NonNull. + Default False. + **extra_args (optional, Dict): Not used. + """ + def __init__( self, type, diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py index 8116a827..1d3e99d8 100644 --- a/graphene/types/inputobjecttype.py +++ b/graphene/types/inputobjecttype.py @@ -36,7 +36,29 @@ class InputObjectType(UnmountedType, BaseType): An input object defines a structured collection of fields which may be supplied to a field argument. - Using `NonNull` will ensure that a value must be provided by the query + Using ``graphene.NonNull`` will ensure that a input value must be provided by the query. + + All class attributes of ``graphene.InputObjectType`` are implicitly mounted as InputField + using the below Meta class options. + + .. code:: python + + class Person(graphene.InputObjectType): + first_name = graphene.String(required=True) # implicitly mounted as Input Field + last_name = graphene.InputField(String, description='Surname') # explicitly mounted as Input Field + + The fields on an input object type can themselves refer to input object types, but you can't + mix input and output types in your schema. + + Meta class options (optional): + name (str): the name of the GraphQL type (must be unique in schema). Defaults to class + name. + description (str): the description of the GraphQL type in the schema. Defaults to class + docstring. + container (class): A class reference for a value object that allows for + attribute initialization and access. Default InputObjectTypeContainer. + fields (Dict[str, graphene.InputField]): Dictionary of field name to InputField. Not + recommended to use (prefer class attributes). """ @classmethod diff --git a/graphene/types/interface.py b/graphene/types/interface.py index f2c9749c..2148259b 100644 --- a/graphene/types/interface.py +++ b/graphene/types/interface.py @@ -22,6 +22,26 @@ class Interface(BaseType): is used to describe what types are possible, what fields are in common across all types, as well as a function to determine which type is actually used when the field is resolved. + + .. code:: python + + class HasAddress(graphene.Interface): + class Meta: + description = 'Address fields' + + address1 = String() + address2 = String() + + If a field returns an Interface Type, the ambiguous type of the object can be determined using + ``resolve_type`` on Interface and an ObjectType with ``Meta.possible_types`` or ``is_type_of``. + + Meta: + name (str): the name of the GraphQL type (must be unique in schema). Defaults to class + name. + description (str): the description of the GraphQL type in the schema. Defaults to class + docstring. + fields (Dict[str, graphene.Field]): dictionary of field name to Field. Not recommended to + use (prefer class attributes). """ @classmethod diff --git a/graphene/types/json.py b/graphene/types/json.py index 495943a9..6b87ae6e 100644 --- a/graphene/types/json.py +++ b/graphene/types/json.py @@ -8,7 +8,12 @@ from .scalars import Scalar class JSONString(Scalar): - """JSON String""" + """ + Allows use of a JSON String for input / output from the GraphQL schema. + + Use of this type is *not recommended* as you lose the benefits of having a defined, static + schema (one of the key benefits of GraphQL). + """ @staticmethod def serialize(dt): diff --git a/graphene/types/mutation.py b/graphene/types/mutation.py index dd09e461..372daeec 100644 --- a/graphene/types/mutation.py +++ b/graphene/types/mutation.py @@ -22,7 +22,44 @@ class MutationOptions(ObjectTypeOptions): class Mutation(ObjectType): """ - Mutation Type Definition + Object Type Definition (mutation field) + + Mutation is a convenience type that helps us build a Field which takes Arguments and returns a + mutation Output ObjectType. + + .. code:: python + + class CreatePerson(graphene.Mutation): + class Arguments: + name = graphene.String() + + ok = graphene.Boolean() + person = graphene.Field(Person) + + def mutate(parent, info, name): + person = Person(name=name) + ok = True + return CreatePerson(person=person, ok=ok) + + class Mutation(graphene.ObjectType): + create_person = CreatePerson.Field() + + Meta class options (optional): + output (graphene.ObjectType): Or ``Output`` inner class with attributes on Mutation class. + Or attributes from Mutation class. Fields which can be returned from this mutation + field. + resolver (Callable resolver method): Or ``mutate`` method on Mutation class. Perform data + change and return output. + arguments (Dict[str, graphene.Argument]): Or ``Arguments`` inner class with attributes on + Mutation class. Arguments to use for the mutation Field. + name (str): the name of the GraphQL type (must be unique in schema). Defaults to class + name. + description (str): the description of the GraphQL type in the schema. Defaults to class + docstring. + interfaces (Iterable[graphene.Interface]): GraphQL interfaces to extend with the payload + object. All fields from interface will be included in this object's schema. + fields (Dict[str, graphene.Field]): dictionary of field name to Field. Not recommended to + use (prefer class attributes or ``Meta.output``). """ @classmethod @@ -80,6 +117,7 @@ class Mutation(ObjectType): def Field( cls, name=None, description=None, deprecation_reason=None, required=False ): + """ Mount instance of mutation Field. """ return Field( cls._meta.output, args=cls._meta.arguments, diff --git a/graphene/types/objecttype.py b/graphene/types/objecttype.py index be4addb2..1017cb8e 100644 --- a/graphene/types/objecttype.py +++ b/graphene/types/objecttype.py @@ -22,6 +22,62 @@ class ObjectType(BaseType): Almost all of the GraphQL types you define will be object types. Object types have a name, but most importantly describe their fields. + + The name of the type defined by an _ObjectType_ defaults to the class name. The type + description defaults to the class docstring. This can be overriden by adding attributes + to a Meta inner class. + + The class attributes of an _ObjectType_ are mounted as instances of ``graphene.Field``. + + Methods starting with ``resolve_`` are bound as resolvers of the matching Field + name. If no resolver is provided, the default resolver is used. + + Ambiguous types with Interface and Union can be determined through``is_type_of`` method and + ``Meta.possible_types`` attribute. + + .. code:: python + + class Person(ObjectType): + class Meta: + description = 'A human' + + first_name = graphene.String() # implicitly mounted as Field + last_name = graphene.Field(String) # explicitly mounted as Field + + def resolve_last_name(parent, info): + return last_name + + ObjectType must be mounted using ``graphene.Field``. + + .. code:: python + + graphene.Feild(Person, description='My favorite person')``. + + Meta class options (optional): + name (str): the name of the GraphQL type (must be unique in schema). Defaults to class + name. + description (str): the description of the GraphQL type in the schema. Defaults to class + docstring. + interfaces (Iterable[graphene.Interface]): GraphQL interfaces to extend with this object. + all fields from interface will be included in this object's schema. + possible_types (Iterable[class]): used to test parent value object via isintance to see if + this type can be used to resolve an ambigous type (interface, union). + default_resolver (any Callable resolver): Override the default resolver for this + type. Defaults to graphene default resolver which returns an attribute or dictionary + key with the same name as the field. + fields (Dict[str, graphene.Field]): dictionary of field name to Field. Not recommended to + use (prefer class attributes). + + An _ObjectType_ can be used as a simple value object by creating an instance of the class. + + .. code:: python + + p = Person(first_name='Bob', last_name='Roberts') + assert p.first_name == 'Bob' + + Args: + *args (List[Any]): positional values to use for Field values of value object + **kwargs (Dict[str: Any]): keyword arguments to use for Field values of value object """ @classmethod diff --git a/graphene/types/structures.py b/graphene/types/structures.py index dde68f0f..44012aed 100644 --- a/graphene/types/structures.py +++ b/graphene/types/structures.py @@ -39,6 +39,12 @@ class List(Structure): A list is a kind of type marker, a wrapping type which points to another type. Lists are often created within the context of defining the fields of an object type. + + List indicates that many values will be returned (or input) for this field. + + .. code:: python + + field_name = graphene.List(graphene.String, description='There will be many values') """ def __str__(self): @@ -63,6 +69,14 @@ class NonNull(Structure): usually the id field of a database row will never be null. Note: the enforcement of non-nullability occurs within the executor. + + NonNull can also be indicated on all Mounted types with the argument ``required``. + + .. code:: python + + field_name = graphene.NonNull(graphene.String, description='This field will not be null') + another_field = graphene.String(required=True, description='This is equivalent to the above') + """ def __init__(self, *args, **kwargs): diff --git a/graphene/types/union.py b/graphene/types/union.py index dc207e8e..e05d7882 100644 --- a/graphene/types/union.py +++ b/graphene/types/union.py @@ -19,6 +19,32 @@ class Union(UnmountedType, BaseType): When a field can return one of a heterogeneous set of types, a Union type is used to describe what types are possible as well as providing a function to determine which type is actually used when the field is resolved. + + The schema in this example can take a search text and return any of the GraphQL object types + indicated: Human, Droid or Startship. + + Ambigous return types can be resolved on each ObjectType through ``Meta.possible_types`` + attribute or ``is_type_of`` method. Or by implementing ``resolve_type`` class method on the + Union. + + .. code:: python + + class SearchResult(graphene.Union): + class Meta: + types = (Human, Droid, Starship) + + class Query(graphene.ObjectType): + search = graphene.List(SearchResult.Field( + search_text=String(description='Value to search for')) + ) + + Meta: + types (Iterable[graphene.ObjectType)]: Required. Collection of types that may be returned + by this Union for the graphQL schema. + name (optional, str): the name of the GraphQL type (must be unique in schema). Defaults to class + name. + description (optional, str): the description of the GraphQL type in the schema. Defaults to class + docstring. """ @classmethod diff --git a/graphene/types/unmountedtype.py b/graphene/types/unmountedtype.py index 5bcdab55..dd2045ef 100644 --- a/graphene/types/unmountedtype.py +++ b/graphene/types/unmountedtype.py @@ -6,13 +6,33 @@ class UnmountedType(OrderedType): This class acts a proxy for a Graphene Type, so it can be mounted dynamically as Field, InputField or Argument. - Instead of writing - >>> class MyObjectType(ObjectType): - >>> my_field = Field(String, description='Description here') + Instead of writing: - It let you write - >>> class MyObjectType(ObjectType): - >>> my_field = String(description='Description here') + .. code:: python + + class MyObjectType(ObjectType): + my_field = Field(String, description='Description here') + + It lets you write: + + .. code:: python + + class MyObjectType(ObjectType): + my_field = String(description='Description here') + + It is not used directly, but is inherited by other types and streamlines their use in + different context: + + - Object Type + - Scalar Type + - Enum + - Interface + - Union + + An unmounted type will accept arguments based upon its context (ObjectType, Field or + InputObjectType) and pass it on to the appropriate MountedType (Field, Argument or InputField). + + See each Mounted type reference for more information about valid parameters. """ def __init__(self, *args, **kwargs): diff --git a/graphene/types/uuid.py b/graphene/types/uuid.py index b9687e1e..0628200b 100644 --- a/graphene/types/uuid.py +++ b/graphene/types/uuid.py @@ -8,7 +8,10 @@ from .scalars import Scalar class UUID(Scalar): - """UUID""" + """ + Leverages the internal Python implmeentation of UUID (uuid.UUID) to provide native UUID objects + in fields, resolvers and input. + """ @staticmethod def serialize(uuid):