# GraphQL : GraphQL-core 3
## Overview
A Python port of GraphQL.js, the JavaScript reference implementation for GraphQL.
> [!NOTE] Version Correlations
> GraphQL-core v3.2.4 is up-to-date with GraphQL.js v16.8.2 and supports Python version 3.6 to 3.12.
>
> Changes in the major version of GraphQL.js are reflected in the minor version of GraphQL-core. This means there can be breaking changes in the API when the minor version changes, and only patch releases are fully backward compatible. Therefore, we recommend something like `=~ 3.2.0` as version specifier.
```bash
$ pip install graphql-core
```
**Components**
- a type system that you define
- a query language that you use to query the API
- an execution and validation engine
#### Imports
```python
graphql.error. GraphQLError
graphql.execution. ExecutionContext
graphql.execution. Middleware
graphql.execution. subscribe
graphql.graphql. graphql # coro that accepts coros (and *only* coros?)
graphql.graphql. graphql_sync # all resolvers must be sync functions
graphql.language. DocumentNode
graphql.language. Source
graphql.language. parse
graphql.type. GraphQLArgument
graphql.type. GraphQLBoolean
graphql.type. GraphQLEnumType
graphql.type. GraphQLEnumValue
graphql.type. GraphQLField
graphql.type. GraphQLFloat
graphql.type. GraphQLID
graphql.type. GraphQLInputField
graphql.type. GraphQLInputObjectType
graphql.type. GraphQLInt
graphql.type. GraphQLInterfaceType
graphql.type. GraphQLList
graphql.type. GraphQLNonNull
graphql.type. GraphQLObjectType
graphql.type. GraphQLScalarType
graphql.type. GraphQLSchema
graphql.type. GraphQLString
graphql.type. GraphQLUnionType
graphql.utilities. build_ast_schema
graphql.utilities. build_client_schema
graphql.utilities. build_schema
graphql.utilities. extend_schema
graphql.utilities. get_introspection_query
graphql.utilities. print_schema
graphql.validation. validate
```
## Schemas
```
str -> SDL
DocumentNode -> AST; result of parse()
GraphQLSchema -> tree of type objects; result of build_schema()
```
```python
schema = GraphQLSchema(
query = GraphQLObjectType(
name = "RootQueryType"
fields = {
"hello": GraphQLField(
GraphQLString
resolve = lambda obj, info: "world" ) } ) )
sdl = """..."""
schema = build_schema( sdl ) -> GraphQLSchema
doc = parse( sdl ) -> Document # works with schemas and queries
schema = build_ast_schema( doc ) -> GraphQLSchema
sdl = print_schema( schema ) -> str
```
#### Extending
```python
schema = extend_schema( schema, parse( more_sdl ) )
```
## Resolvers
- Resolvers can return a value, a coro, or a list of these.
- You don’t need to provide resolvers for simple attribute access or for fetching items from Python dictionaries.
#### Defining
The standard args (obj+info) are passed as positional, field args are passed as kwargs.
- obj -> root | parent object
- info -> GraphQLResolveInfo — contains info about query execution state + "context" dict with per-request state (like auth)
```python
[async] def resolve_foo( obj, info, ... ):
...
```
#### Binding
```python
# Including in type definition:
GraphQLField( GraphQLString, resolve=resolve_foo )
# Manually attaching to parsed schema:
schema.query_type.fields[ "hero" ].resolve = my_func1
schema.get_type( "Character" ).resolve_type = my_func2
# Manually populate enum values in parsed schema:
for name, value in schema.get_type( "Episode" ).values.items():
value.value = EpisodeEnum[ name ].value
```
#### Resolvers on Objects
Instead of attaching resolver functions to the schema, you can define resolver methods on the resolved objects, starting with the `root_value` object that you can pass to the `graphql()` function when executing a query.
```python
class Root:
def hero( self, info, episode ):
return luke if episode == 5 else artoo
def human( self, info, id ):
return human_data.get( id )
def droid( self, info, id ):
return droid_data.get( id )
graphql_sync( schema, "...", Root() )
```
## Execution
```python
await graphql( ... ) -> ExecutionResult
graphql_sync( ... ) -> ExecutionResult
schema # GraphQLSchema
source # str | graphql.language.Source (query)
root_value = None # Any
context_value = None # Any; will be attached to `info` resolver arg
variable_values = None # { str -> Any }
operation_name = None # str; only needed if `source` contains multiple operations
field_resolver = None # GraphQLFieldResolver
type_resolver = None # GraphQLTypeResolver
middleware = None # Middleware
execution_context_class = None # ExecutionContext
# only graphql()
is_awaitable = None # Callable( Any, bool )
# only graphql_sync()
check_sync = False
# field_resolver – A resolver function to use when one is not provided by the schema.
# If not provided, the default field resolver is used (which looks for a value or method on the source value with the field’s name).
# type_resolver – A type resolver function to use when none is provided by the schema.
# If not provided, the default type resolver is used (which looks for a `__typename` field or alternatively calls the `is_type_of()` method).
```
#### Results
```python
ExecutionResult( data={ "hello": "world" }, errors=None )
ExecutionResult(
data = None
errors = [
GraphQLError(
"Cannot query field 'mello' on type 'RootQueryType'."
locations = [ SourceLocation( line=1, column=3 ) ]
)
]
)
ExecutionResult(
data = { "hero": { "name": "Luke Skywalker", "secretBackstory": None } }
errors = [
GraphQLError(
"secretBackstory is secret"
locations = [ SourceLocation( line=5, column=9 ) ]
path = [ "hero", "secretBackstory" ]
)
]
)
```
## Subscriptions
You'll need to maintain a persistent channel to the client (often realized via WebSockets) to push these results back.
```python
subscribe() -> aiter: ExecutionResult
```
## Building a Type Schema
The example from the docs.
#### SDL
```
enum Episode { NEWHOPE, EMPIRE, JEDI }
interface Character {
id : String!
name : String
friends : [ Character ]
appearsIn : [ Episode ]
}
type Human implements Character {
id : String!
name : String
friends : [ Character ]
appearsIn : [ Episode ]
homePlanet : String
}
type Droid implements Character {
id : String!
name : String
friends : [ Character ]
appearsIn : [ Episode ]
primaryFunction : String
}
type Query {
hero( episode: Episode ): Character
human( id: String! ): Human
droid( id: String! ): Droid
}
```
#### enum Episode
```python
episode_enum = GraphQLEnumType(
"Episode"
{ "NEWHOPE" : 4
"EMPIRE" : 5
"JEDI" : 6 }
description = "One of the films in the Star Wars Trilogy"
)
-or-
episode_enum = GraphQLEnumType(
"Episode"
{ "NEWHOPE" : GraphQLEnumValue( 4, description="Released in 1977." ),
"EMPIRE" : GraphQLEnumValue( 5, description="Released in 1980." ),
"JEDI" : GraphQLEnumValue( 6, description="Released in 1983." ) }
description = "One of the films in the Star Wars Trilogy"
)
-or-
class EpisodeEnum( enum.Enum ):
NEWHOPE = 4
EMPIRE = 5
JEDI = 6
episode_enum = GraphQLEnumType(
"Episode"
EpisodeEnum
description = "One of the films in the Star Wars Trilogy"
)
```
#### interface Character
```python
character_interface = GraphQLInterfaceType(
"Character"
lambda: dict(
id = GraphQLField( GraphQLNonNull( GraphQLString ), description="The id of the character." )
name = GraphQLField( GraphQLString, description="The name of the character." )
friends = GraphQLField( GraphQLList( character_interface ), description="The friends of the character, or an empty list if they have none." )
appearsIn = GraphQLField( GraphQLList( episode_enum ), description="Which movies they appear in." )
secretBackstory = GraphQLField( GraphQLString, description="All secrets about their past." )
)
resolve_type = get_character_type
description = "A character in the Star Wars Trilogy"
)
```
> [!NOTE] Thunks
> Note that we did not pass the dictionary of fields to the GraphQLInterfaceType directly, but using a lambda function (a so-called “thunk”). This is necessary because the fields are referring back to the character interface that we are just defining. Otherwise, you can pass everything directly.
#### type Human
```python
human_type = GraphQLObjectType(
"Human"
lambda: dict(
id = GraphQLField( GraphQLNonNull( GraphQLString ), description="The id of the human." )
name = GraphQLField( GraphQLString, description="The name of the human." )
friends = GraphQLField( GraphQLList( character_interface ), resolve=get_friends, description="The friends of the human, or an empty list if they have none." )
appearsIn = GraphQLField( GraphQLList( episode_enum ), description="Which movies they appear in." )
homePlanet = GraphQLField( GraphQLString, description="The home planet of the human, or null if unknown." )
secretBackstory = GraphQLField( GraphQLString, resolve=get_secret_backstory, description="Where are they from and how they came to be who they are." )
),
interfaces = [ character_interface ]
description = "A humanoid creature in the Star Wars universe."
)
```
#### type Droid
```python
droid_type = GraphQLObjectType(
"Droid"
lambda: dict(
id = GraphQLField( GraphQLNonNull( GraphQLString ), description="The id of the droid." )
name = GraphQLField( GraphQLString, description="The name of the droid." )
friends = GraphQLField( GraphQLList( character_interface ), resolve=get_friends, description="The friends of the droid, or an empty list if they have none." )
appearsIn = GraphQLField( GraphQLList( episode_enum ), description="Which movies they appear in." )
secretBackstory = GraphQLField( GraphQLString, resolve=get_secret_backstory, description="Construction date and the name of the designer." )
primaryFunction = GraphQLField( GraphQLString, description="The primary function of the droid." )
},
interfaces = [ character_interface ]
description = "A mechanical creature in the Star Wars universe."
)
```
#### type Query
```python
query_type = GraphQLObjectType(
"Query"
lambda: dict(
hero = GraphQLField( character_interface, resolve=get_hero, args=dict( episode = GraphQLArgument(
episode_enum, description="If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode." ) ) )
human = GraphQLField( human_type, resolve=get_human, args=dict( id = GraphQLArgument( GraphQLNonNull( GraphQLString ), description="id of the human" ) ) )
droid = GraphQLField( droid_type, resolve=get_droid, args=dict( id = GraphQLArgument( GraphQLNonNull( GraphQLString ), description="id of the droid" ) ) )
)
)
```