Skip to content

Instantly share code, notes, and snippets.

@jasonphillips
Last active April 7, 2020 12:38
Show Gist options
  • Save jasonphillips/d80642fc33d98cb34bad131adfcf6ed8 to your computer and use it in GitHub Desktop.
Save jasonphillips/d80642fc33d98cb34bad131adfcf6ed8 to your computer and use it in GitHub Desktop.
python graphql-tools imitation
import graphql
# build_executable schema
#
# accepts schema_definition (string) and resolvers (object) in style of graphql-tools
# returns a schema ready for execution
def build_executable_schema(schema_definition, resolvers):
ast = graphql.parse(schema_definition)
schema = graphql.build_ast_schema(ast)
for typeName in resolvers:
fieldType = schema.get_type(typeName)
for fieldName in resolvers[typeName]:
if fieldType is graphql.GraphQLScalarType:
fieldType.fields[fieldName].resolver = resolvers[typeName][fieldName]
continue
field = fieldType.fields[fieldName]
field.resolver = resolvers[typeName][fieldName]
if not fieldType.fields: continue
for remaining in fieldType.fields:
if not fieldType.fields[remaining].resolver:
fieldType.fields[remaining].resolver = \
lambda value, info, _r=remaining, **args: value[_r]
return schema
import graphql
import json
from graphql_tools import build_executable_schema
source_schema = """
schema {
query: RootQuery
}
type RootQuery {
officers: [Officer]
}
type Officer {
title: String
first: String
last: String
uniform: Uniform
}
type Uniform {
pips: Float
}
"""
resolvers = {
'RootQuery': {
# returning direct values, but would normally load fetch db with some info.context
'officers': lambda value, info, **args: [
dict(first='william', last='riker'),
dict(first='geordi', last='laforge'),
]
},
'Officer': {
# only declaring the field here which is computed
'title': lambda value, info, **args: 'Officer: %(first)s %(last)s' % value,
# and the connection
'uniform': lambda value, info, **args: value['first']=='geordi' and {'i':2.5} or {'i':3},
},
'Uniform': {
'pips': lambda value, info, **args: value['i'],
}
}
my_schema = build_executable_schema(source_schema, resolvers)
executed = graphql.graphql(my_schema, """
query Example {
officers {
first
last
title
uniform { pips }
}
}
""")
print(json.dumps(executed.data, indent=4))
{
"officers": [
{
"first": "william",
"last": "riker",
"title": "Officer: william riker",
"uniform": {
"pips": 3.0
}
},
{
"first": "geordi",
"last": "laforge",
"title": "Officer: geordi laforge",
"uniform": {
"pips": 2.5
}
}
]
}
@mingzhou
Copy link

mingzhou commented Apr 9, 2018

Great Job!
I opened the issue graphql-python/graphene#704 .

I think it's a better idea to design schema by DSL format. I don't know much about why we have to get a extra graphene schema layer. Even though the graphene schema layer is necessary, we still must have a DSL => graphene schema parser.

I'm quite confused that why there are two types of definition. Graphene schema definition graphene.types.schema.Schema and graphql-core schema definition graphql.type.schema.GraphQLSchema.

Since graphene.types.schema.Schema is extended from graphql.type.schema.GraphQLSchema, how could I get graphene.types.schema.Schema from graphq.parse(DSL file)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment