GraphQL Framework for Python providing declarative schema construction and query execution
—
Graphene provides a comprehensive GraphQL type system through Python classes that mirror the GraphQL specification. This includes object types for data structures, scalar types for primitive values, composite types for complex relationships, input types for mutations and queries, and field definitions for connecting data.
Define GraphQL object types that represent data structures with typed fields and resolvers.
class ObjectType(BaseType):
"""
Primary GraphQL object type for defining data structures.
Features:
- Automatic dataclass integration for field access
- Field collection via metaclass
- Interface implementation support
- Custom resolver binding
Meta Options:
interfaces: List of interfaces this type implements
possible_types: For interface resolution
default_resolver: Default field resolver function
fields: Custom field definitions
Usage:
class Person(graphene.ObjectType):
name = graphene.String(required=True)
age = graphene.Int()
def resolve_age(self, info):
return self.calculate_age()
"""Define individual fields on GraphQL types with arguments, resolvers, and metadata.
class Field(MountedType):
"""
Defines individual fields on GraphQL types.
Parameters:
type_: The GraphQL type for this field
args: Dictionary of field arguments
resolver: Custom resolver function
source: Source field name for automatic resolution
deprecation_reason: Deprecation message
name: Field name (defaults to Python attribute name)
description: Field description
required: Whether field is NonNull (alternative to NonNull wrapper)
default_value: Default value for the field
Methods:
wrap_resolve(parent_resolver): Wraps resolver for field resolution
wrap_subscribe(parent_subscribe): Wraps subscription resolver
"""
def Field(type_, **kwargs):
"""
Create a field with the specified type and options.
Args:
type_: GraphQL type (String, Int, ObjectType, etc.)
resolver: Custom resolver function
args: Field arguments
required: Make field non-null
description: Field documentation
deprecation_reason: Mark field as deprecated
Returns:
Field instance
"""Built-in GraphQL scalar types for primitive values with automatic serialization and parsing.
class String(Scalar):
"""
UTF-8 text representation with automatic type coercion.
Features:
- Coerces various Python types to string
- UTF-8 encoding/decoding
- Null value handling
"""
class Int(Scalar):
"""
32-bit signed integers with range validation.
Range: -2^31 to 2^31-1
Features:
- Automatic range checking
- Float to int conversion with validation
- Null value handling
"""
class BigInt(Scalar):
"""
Unlimited precision integers.
Features:
- No range limitations
- Handles Python's arbitrary precision integers
- String/numeric parsing
"""
class Float(Scalar):
"""
IEEE 754 double-precision floating point numbers.
Features:
- Standard floating point operations
- Automatic type coercion from int/string
- NaN and infinity handling
"""
class Boolean(Scalar):
"""
True/false values with Python truthiness conversion.
Features:
- Uses Python's bool() function for coercion
- Handles various truthy/falsy values
"""
class ID(Scalar):
"""
Unique identifier that accepts string or int, serializes to string.
Features:
- Accepts both string and integer input
- Always serializes to string format
- Used for object identification
"""class UUID(Scalar):
"""
Native UUID type using Python's uuid.UUID.
Features:
- Automatic UUID validation
- String to UUID conversion
- Standard UUID format support
"""
class DateTime(Scalar):
"""
ISO 8601 datetime representation with timezone support.
Features:
- Uses dateutil.parser.isoparse for flexible parsing
- Timezone-aware datetime support
- ISO 8601 string serialization
"""
class Date(Scalar):
"""
ISO 8601 date representation (YYYY-MM-DD).
Features:
- Handles datetime.date objects
- ISO date string parsing
- Date-only operations
"""
class Time(Scalar):
"""
ISO 8601 time representation (HH:MM:SS).
Features:
- Handles datetime.time objects
- Time-only operations
- Optional microsecond precision
"""
class Decimal(Scalar):
"""
Python Decimal type for precise numeric values.
Features:
- Maintains decimal precision
- String/numeric parsing
- Financial calculations support
"""
class JSONString(Scalar):
"""
JSON-encoded strings (not recommended for schema design).
Warning: Not recommended for new schemas
Features:
- Automatic JSON serialization/deserialization
- Bypasses GraphQL type system
"""
class Base64(Scalar):
"""
Base64-encoded binary data.
Features:
- Automatic base64 encoding/decoding
- UTF-8 string handling
- Binary data transport
"""Complex GraphQL types for representing relationships and polymorphism.
class Interface(BaseType):
"""
Defines shared fields across multiple object types.
Features:
- Field inheritance for implementing types
- Type resolution at query time
- Cannot be instantiated directly
Meta Options:
fields: Field definitions
interfaces: Other interfaces this extends
Methods:
resolve_type(instance, info): Determines concrete type from instance
Usage:
class Node(graphene.Interface):
id = graphene.ID(required=True)
@classmethod
def resolve_type(cls, instance, info):
return type(instance).__name__
"""
class Union(UnmountedType, BaseType):
"""
Represents one of several possible object types.
Features:
- Type resolution at query time
- No shared fields between types
- Useful for search results or heterogeneous collections
Meta Options:
types: Required list of ObjectTypes in the union
Methods:
resolve_type(instance, info): Type resolution for union members
Usage:
class SearchResult(graphene.Union):
class Meta:
types = (Person, Company, Product)
"""
class Enum(EnumMeta):
"""
Defines static set of named values.
Features:
- Automatic Python Enum integration
- Custom equality/hashing for enum values
- Dynamic enum creation
Meta Options:
enum: Python Enum class to use
description: Enum description
deprecation_reason: Mark enum as deprecated
Class Methods:
from_enum(python_enum): Create GraphQL enum from Python enum
Usage:
class Color(graphene.Enum):
RED = 1
GREEN = 2
BLUE = 3
# Or from Python enum
from enum import Enum as PyEnum
class Status(PyEnum):
ACTIVE = "active"
INACTIVE = "inactive"
GraphQLStatus = graphene.Enum.from_enum(Status)
"""Types for accepting structured input data in mutations and query arguments.
class InputObjectType(UnmountedType, BaseType):
"""
Structured input data for mutations and queries.
Features:
- Automatic InputField mounting
- Container class generation for value objects
- Default value handling
- Validation support
Meta Options:
container: Custom container class for input values
fields: Custom field definitions
Usage:
class PersonInput(graphene.InputObjectType):
name = graphene.String(required=True)
age = graphene.Int()
email = graphene.String()
"""
class InputField(MountedType):
"""
Individual input fields on InputObjectType.
Parameters:
type_: Input field type (no Interface/Union types allowed)
name: Field name
default_value: Default value for optional fields
deprecation_reason: Deprecation message
description: Field description
required: Whether field is NonNull
Restrictions:
- No arguments (unlike regular Field)
- Cannot use Interface or Union types
- Only input types allowed
Usage:
email = graphene.InputField(
graphene.String,
description="User email address",
required=True
)
"""
class Argument(MountedType):
"""
Field arguments for queries and mutations.
Parameters:
type_: Argument type
default_value: Default value for optional arguments
deprecation_reason: Deprecation message
description: Argument description
name: Argument name
required: Whether argument is NonNull
Features:
- Automatic conversion from UnmountedTypes
- Argument validation
- Default value handling
Usage:
def resolve_users(self, info, limit=graphene.Argument(graphene.Int, default_value=10)):
return User.objects.all()[:limit]
"""Wrappers for modifying type nullability and creating lists.
class List(Structure):
"""
Array/list type wrapper for GraphQL lists.
Features:
- Type-safe list operations
- Nested list support
- Null item handling
Usage:
users = graphene.List(User) # [User]
matrix = graphene.List(graphene.List(graphene.Int)) # [[Int]]
"""
class NonNull(Structure):
"""
Non-nullable type wrapper for required fields.
Features:
- Prevents null values
- Validation at execution time
- Cannot be nested (NonNull(NonNull(T)) is invalid)
Usage:
name = graphene.NonNull(graphene.String) # String!
# Or use required=True
name = graphene.String(required=True)
"""Advanced types for complex scenarios and runtime behavior.
class Dynamic(MountedType):
"""
Runtime type resolution for lazy fields and circular references.
Parameters:
type_: Function that returns the actual type
with_schema: Whether to pass schema to type function
Methods:
get_type(schema=None): Resolves type at schema build time
Usage:
# Resolve circular reference
def get_user_type():
return User
friends = graphene.Dynamic(get_user_type)
# With schema access
def get_type_with_schema(schema):
return schema.get_type('User')
user = graphene.Dynamic(get_type_with_schema, with_schema=True)
"""
class Scalar(GraphQLScalar):
"""
Base class for custom scalar types.
Abstract Methods:
serialize(value): Convert internal value to transport format
parse_value(value): Parse transport value to internal format
parse_literal(ast_node): Parse AST literal to internal format
Usage:
class EmailScalar(graphene.Scalar):
@staticmethod
def serialize(email):
return str(email)
@staticmethod
def parse_value(value):
if not re.match(r'^[^@]+@[^@]+\.[^@]+$', value):
raise ValueError('Invalid email format')
return value
@staticmethod
def parse_literal(node):
if isinstance(node, StringValueNode):
return EmailScalar.parse_value(node.value)
raise ValueError('Expected string value')
"""import graphene
class Address(graphene.ObjectType):
street = graphene.String(required=True)
city = graphene.String(required=True)
country = graphene.String(required=True)
postal_code = graphene.String()
class Person(graphene.ObjectType):
# Basic fields
name = graphene.String(required=True, description="Full name")
age = graphene.Int(description="Age in years")
email = graphene.String()
# Complex fields
address = graphene.Field(Address)
friends = graphene.List(lambda: Person) # Self-reference
# Field with arguments
posts = graphene.List(
'Post', # String reference to avoid circular import
limit=graphene.Argument(graphene.Int, default_value=10)
)
# Custom resolver
def resolve_posts(self, info, limit=10):
return get_posts_for_user(self.id, limit)
# Computed field
display_name = graphene.String()
def resolve_display_name(self, info):
return f"{self.name} ({self.age})"class CreatePersonInput(graphene.InputObjectType):
name = graphene.String(required=True)
age = graphene.Int()
email = graphene.String()
address = graphene.Field('AddressInput')
class AddressInput(graphene.InputObjectType):
street = graphene.String(required=True)
city = graphene.String(required=True)
country = graphene.String(required=True)
postal_code = graphene.String()
class CreatePerson(graphene.Mutation):
class Arguments:
input = CreatePersonInput(required=True)
person = graphene.Field(Person)
success = graphene.Boolean()
def mutate(self, info, input):
# Access input fields
person_data = {
'name': input.name,
'age': input.age,
'email': input.email
}
if input.address:
person_data['address'] = {
'street': input.address.street,
'city': input.address.city,
'country': input.address.country,
'postal_code': input.address.postal_code
}
# Create person
person = create_person(person_data)
return CreatePerson(person=person, success=True)import graphene
import re
from datetime import datetime
from graphql.language.ast import StringValueNode
class EmailType(graphene.Scalar):
"""Email address scalar with validation."""
@staticmethod
def serialize(email):
"""Serialize email to string."""
return str(email)
@staticmethod
def parse_value(value):
"""Parse email from input value."""
if not isinstance(value, str):
raise ValueError(f"Expected string, got {type(value).__name__}")
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, value):
raise ValueError(f"Invalid email format: {value}")
return value
@staticmethod
def parse_literal(node):
"""Parse email from AST literal."""
if isinstance(node, StringValueNode):
return EmailType.parse_value(node.value)
raise ValueError("Expected string literal for email")
# Usage in schema
class User(graphene.ObjectType):
name = graphene.String()
email = EmailType() # Custom scalar
verified_at = graphene.DateTime()Install with Tessl CLI
npx tessl i tessl/pypi-graphene