0
# Type System
1
2
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.
3
4
## Capabilities
5
6
### Object Types
7
8
Define GraphQL object types that represent data structures with typed fields and resolvers.
9
10
```python { .api }
11
class ObjectType(BaseType):
12
"""
13
Primary GraphQL object type for defining data structures.
14
15
Features:
16
- Automatic dataclass integration for field access
17
- Field collection via metaclass
18
- Interface implementation support
19
- Custom resolver binding
20
21
Meta Options:
22
interfaces: List of interfaces this type implements
23
possible_types: For interface resolution
24
default_resolver: Default field resolver function
25
fields: Custom field definitions
26
27
Usage:
28
class Person(graphene.ObjectType):
29
name = graphene.String(required=True)
30
age = graphene.Int()
31
32
def resolve_age(self, info):
33
return self.calculate_age()
34
"""
35
```
36
37
### Field Definitions
38
39
Define individual fields on GraphQL types with arguments, resolvers, and metadata.
40
41
```python { .api }
42
class Field(MountedType):
43
"""
44
Defines individual fields on GraphQL types.
45
46
Parameters:
47
type_: The GraphQL type for this field
48
args: Dictionary of field arguments
49
resolver: Custom resolver function
50
source: Source field name for automatic resolution
51
deprecation_reason: Deprecation message
52
name: Field name (defaults to Python attribute name)
53
description: Field description
54
required: Whether field is NonNull (alternative to NonNull wrapper)
55
default_value: Default value for the field
56
57
Methods:
58
wrap_resolve(parent_resolver): Wraps resolver for field resolution
59
wrap_subscribe(parent_subscribe): Wraps subscription resolver
60
"""
61
62
def Field(type_, **kwargs):
63
"""
64
Create a field with the specified type and options.
65
66
Args:
67
type_: GraphQL type (String, Int, ObjectType, etc.)
68
resolver: Custom resolver function
69
args: Field arguments
70
required: Make field non-null
71
description: Field documentation
72
deprecation_reason: Mark field as deprecated
73
74
Returns:
75
Field instance
76
"""
77
```
78
79
### Scalar Types
80
81
Built-in GraphQL scalar types for primitive values with automatic serialization and parsing.
82
83
#### Basic Scalars
84
85
```python { .api }
86
class String(Scalar):
87
"""
88
UTF-8 text representation with automatic type coercion.
89
90
Features:
91
- Coerces various Python types to string
92
- UTF-8 encoding/decoding
93
- Null value handling
94
"""
95
96
class Int(Scalar):
97
"""
98
32-bit signed integers with range validation.
99
100
Range: -2^31 to 2^31-1
101
Features:
102
- Automatic range checking
103
- Float to int conversion with validation
104
- Null value handling
105
"""
106
107
class BigInt(Scalar):
108
"""
109
Unlimited precision integers.
110
111
Features:
112
- No range limitations
113
- Handles Python's arbitrary precision integers
114
- String/numeric parsing
115
"""
116
117
class Float(Scalar):
118
"""
119
IEEE 754 double-precision floating point numbers.
120
121
Features:
122
- Standard floating point operations
123
- Automatic type coercion from int/string
124
- NaN and infinity handling
125
"""
126
127
class Boolean(Scalar):
128
"""
129
True/false values with Python truthiness conversion.
130
131
Features:
132
- Uses Python's bool() function for coercion
133
- Handles various truthy/falsy values
134
"""
135
136
class ID(Scalar):
137
"""
138
Unique identifier that accepts string or int, serializes to string.
139
140
Features:
141
- Accepts both string and integer input
142
- Always serializes to string format
143
- Used for object identification
144
"""
145
```
146
147
#### Extended Scalars
148
149
```python { .api }
150
class UUID(Scalar):
151
"""
152
Native UUID type using Python's uuid.UUID.
153
154
Features:
155
- Automatic UUID validation
156
- String to UUID conversion
157
- Standard UUID format support
158
"""
159
160
class DateTime(Scalar):
161
"""
162
ISO 8601 datetime representation with timezone support.
163
164
Features:
165
- Uses dateutil.parser.isoparse for flexible parsing
166
- Timezone-aware datetime support
167
- ISO 8601 string serialization
168
"""
169
170
class Date(Scalar):
171
"""
172
ISO 8601 date representation (YYYY-MM-DD).
173
174
Features:
175
- Handles datetime.date objects
176
- ISO date string parsing
177
- Date-only operations
178
"""
179
180
class Time(Scalar):
181
"""
182
ISO 8601 time representation (HH:MM:SS).
183
184
Features:
185
- Handles datetime.time objects
186
- Time-only operations
187
- Optional microsecond precision
188
"""
189
190
class Decimal(Scalar):
191
"""
192
Python Decimal type for precise numeric values.
193
194
Features:
195
- Maintains decimal precision
196
- String/numeric parsing
197
- Financial calculations support
198
"""
199
200
class JSONString(Scalar):
201
"""
202
JSON-encoded strings (not recommended for schema design).
203
204
Warning: Not recommended for new schemas
205
Features:
206
- Automatic JSON serialization/deserialization
207
- Bypasses GraphQL type system
208
"""
209
210
class Base64(Scalar):
211
"""
212
Base64-encoded binary data.
213
214
Features:
215
- Automatic base64 encoding/decoding
216
- UTF-8 string handling
217
- Binary data transport
218
"""
219
```
220
221
### Composite Types
222
223
Complex GraphQL types for representing relationships and polymorphism.
224
225
```python { .api }
226
class Interface(BaseType):
227
"""
228
Defines shared fields across multiple object types.
229
230
Features:
231
- Field inheritance for implementing types
232
- Type resolution at query time
233
- Cannot be instantiated directly
234
235
Meta Options:
236
fields: Field definitions
237
interfaces: Other interfaces this extends
238
239
Methods:
240
resolve_type(instance, info): Determines concrete type from instance
241
242
Usage:
243
class Node(graphene.Interface):
244
id = graphene.ID(required=True)
245
246
@classmethod
247
def resolve_type(cls, instance, info):
248
return type(instance).__name__
249
"""
250
251
class Union(UnmountedType, BaseType):
252
"""
253
Represents one of several possible object types.
254
255
Features:
256
- Type resolution at query time
257
- No shared fields between types
258
- Useful for search results or heterogeneous collections
259
260
Meta Options:
261
types: Required list of ObjectTypes in the union
262
263
Methods:
264
resolve_type(instance, info): Type resolution for union members
265
266
Usage:
267
class SearchResult(graphene.Union):
268
class Meta:
269
types = (Person, Company, Product)
270
"""
271
272
class Enum(EnumMeta):
273
"""
274
Defines static set of named values.
275
276
Features:
277
- Automatic Python Enum integration
278
- Custom equality/hashing for enum values
279
- Dynamic enum creation
280
281
Meta Options:
282
enum: Python Enum class to use
283
description: Enum description
284
deprecation_reason: Mark enum as deprecated
285
286
Class Methods:
287
from_enum(python_enum): Create GraphQL enum from Python enum
288
289
Usage:
290
class Color(graphene.Enum):
291
RED = 1
292
GREEN = 2
293
BLUE = 3
294
295
# Or from Python enum
296
from enum import Enum as PyEnum
297
class Status(PyEnum):
298
ACTIVE = "active"
299
INACTIVE = "inactive"
300
301
GraphQLStatus = graphene.Enum.from_enum(Status)
302
"""
303
```
304
305
### Input Types
306
307
Types for accepting structured input data in mutations and query arguments.
308
309
```python { .api }
310
class InputObjectType(UnmountedType, BaseType):
311
"""
312
Structured input data for mutations and queries.
313
314
Features:
315
- Automatic InputField mounting
316
- Container class generation for value objects
317
- Default value handling
318
- Validation support
319
320
Meta Options:
321
container: Custom container class for input values
322
fields: Custom field definitions
323
324
Usage:
325
class PersonInput(graphene.InputObjectType):
326
name = graphene.String(required=True)
327
age = graphene.Int()
328
email = graphene.String()
329
"""
330
331
class InputField(MountedType):
332
"""
333
Individual input fields on InputObjectType.
334
335
Parameters:
336
type_: Input field type (no Interface/Union types allowed)
337
name: Field name
338
default_value: Default value for optional fields
339
deprecation_reason: Deprecation message
340
description: Field description
341
required: Whether field is NonNull
342
343
Restrictions:
344
- No arguments (unlike regular Field)
345
- Cannot use Interface or Union types
346
- Only input types allowed
347
348
Usage:
349
email = graphene.InputField(
350
graphene.String,
351
description="User email address",
352
required=True
353
)
354
"""
355
356
class Argument(MountedType):
357
"""
358
Field arguments for queries and mutations.
359
360
Parameters:
361
type_: Argument type
362
default_value: Default value for optional arguments
363
deprecation_reason: Deprecation message
364
description: Argument description
365
name: Argument name
366
required: Whether argument is NonNull
367
368
Features:
369
- Automatic conversion from UnmountedTypes
370
- Argument validation
371
- Default value handling
372
373
Usage:
374
def resolve_users(self, info, limit=graphene.Argument(graphene.Int, default_value=10)):
375
return User.objects.all()[:limit]
376
"""
377
```
378
379
### Structure Modifiers
380
381
Wrappers for modifying type nullability and creating lists.
382
383
```python { .api }
384
class List(Structure):
385
"""
386
Array/list type wrapper for GraphQL lists.
387
388
Features:
389
- Type-safe list operations
390
- Nested list support
391
- Null item handling
392
393
Usage:
394
users = graphene.List(User) # [User]
395
matrix = graphene.List(graphene.List(graphene.Int)) # [[Int]]
396
"""
397
398
class NonNull(Structure):
399
"""
400
Non-nullable type wrapper for required fields.
401
402
Features:
403
- Prevents null values
404
- Validation at execution time
405
- Cannot be nested (NonNull(NonNull(T)) is invalid)
406
407
Usage:
408
name = graphene.NonNull(graphene.String) # String!
409
# Or use required=True
410
name = graphene.String(required=True)
411
"""
412
```
413
414
### Special Types
415
416
Advanced types for complex scenarios and runtime behavior.
417
418
```python { .api }
419
class Dynamic(MountedType):
420
"""
421
Runtime type resolution for lazy fields and circular references.
422
423
Parameters:
424
type_: Function that returns the actual type
425
with_schema: Whether to pass schema to type function
426
427
Methods:
428
get_type(schema=None): Resolves type at schema build time
429
430
Usage:
431
# Resolve circular reference
432
def get_user_type():
433
return User
434
435
friends = graphene.Dynamic(get_user_type)
436
437
# With schema access
438
def get_type_with_schema(schema):
439
return schema.get_type('User')
440
441
user = graphene.Dynamic(get_type_with_schema, with_schema=True)
442
"""
443
444
class Scalar(GraphQLScalar):
445
"""
446
Base class for custom scalar types.
447
448
Abstract Methods:
449
serialize(value): Convert internal value to transport format
450
parse_value(value): Parse transport value to internal format
451
parse_literal(ast_node): Parse AST literal to internal format
452
453
Usage:
454
class EmailScalar(graphene.Scalar):
455
@staticmethod
456
def serialize(email):
457
return str(email)
458
459
@staticmethod
460
def parse_value(value):
461
if not re.match(r'^[^@]+@[^@]+\.[^@]+$', value):
462
raise ValueError('Invalid email format')
463
return value
464
465
@staticmethod
466
def parse_literal(node):
467
if isinstance(node, StringValueNode):
468
return EmailScalar.parse_value(node.value)
469
raise ValueError('Expected string value')
470
"""
471
```
472
473
## Usage Examples
474
475
### Creating Custom Object Types
476
477
```python
478
import graphene
479
480
class Address(graphene.ObjectType):
481
street = graphene.String(required=True)
482
city = graphene.String(required=True)
483
country = graphene.String(required=True)
484
postal_code = graphene.String()
485
486
class Person(graphene.ObjectType):
487
# Basic fields
488
name = graphene.String(required=True, description="Full name")
489
age = graphene.Int(description="Age in years")
490
email = graphene.String()
491
492
# Complex fields
493
address = graphene.Field(Address)
494
friends = graphene.List(lambda: Person) # Self-reference
495
496
# Field with arguments
497
posts = graphene.List(
498
'Post', # String reference to avoid circular import
499
limit=graphene.Argument(graphene.Int, default_value=10)
500
)
501
502
# Custom resolver
503
def resolve_posts(self, info, limit=10):
504
return get_posts_for_user(self.id, limit)
505
506
# Computed field
507
display_name = graphene.String()
508
509
def resolve_display_name(self, info):
510
return f"{self.name} ({self.age})"
511
```
512
513
### Working with Input Types
514
515
```python
516
class CreatePersonInput(graphene.InputObjectType):
517
name = graphene.String(required=True)
518
age = graphene.Int()
519
email = graphene.String()
520
address = graphene.Field('AddressInput')
521
522
class AddressInput(graphene.InputObjectType):
523
street = graphene.String(required=True)
524
city = graphene.String(required=True)
525
country = graphene.String(required=True)
526
postal_code = graphene.String()
527
528
class CreatePerson(graphene.Mutation):
529
class Arguments:
530
input = CreatePersonInput(required=True)
531
532
person = graphene.Field(Person)
533
success = graphene.Boolean()
534
535
def mutate(self, info, input):
536
# Access input fields
537
person_data = {
538
'name': input.name,
539
'age': input.age,
540
'email': input.email
541
}
542
543
if input.address:
544
person_data['address'] = {
545
'street': input.address.street,
546
'city': input.address.city,
547
'country': input.address.country,
548
'postal_code': input.address.postal_code
549
}
550
551
# Create person
552
person = create_person(person_data)
553
return CreatePerson(person=person, success=True)
554
```
555
556
### Custom Scalar Example
557
558
```python
559
import graphene
560
import re
561
from datetime import datetime
562
from graphql.language.ast import StringValueNode
563
564
class EmailType(graphene.Scalar):
565
"""Email address scalar with validation."""
566
567
@staticmethod
568
def serialize(email):
569
"""Serialize email to string."""
570
return str(email)
571
572
@staticmethod
573
def parse_value(value):
574
"""Parse email from input value."""
575
if not isinstance(value, str):
576
raise ValueError(f"Expected string, got {type(value).__name__}")
577
578
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
579
if not re.match(email_pattern, value):
580
raise ValueError(f"Invalid email format: {value}")
581
582
return value
583
584
@staticmethod
585
def parse_literal(node):
586
"""Parse email from AST literal."""
587
if isinstance(node, StringValueNode):
588
return EmailType.parse_value(node.value)
589
raise ValueError("Expected string literal for email")
590
591
# Usage in schema
592
class User(graphene.ObjectType):
593
name = graphene.String()
594
email = EmailType() # Custom scalar
595
verified_at = graphene.DateTime()
596
```