Easy to use abstraction layer for GraphQL, with support for Django ORM.
Project description
Easy GraphQL Server
easy_graphql_server provides an easy way to expose a database in GraphQL, using ORM models and web frameworks (so far only Django is supported, but SQLAlchemy & Flask will soon come).
- Easy GraphQL Server
easy_graphql_server can be installed from PyPI using the built-in pip command:
pip install easy-graphql-server
Usage
Expose methods
There are three ways to expose a method in the GraphQL schema.
Calling Schema.expose_query()
and Schema.expose_mutation()
import easy_graphql_server as egs
schema = egs.Schema()
schema.expose_query(
name = 'foo',
input_format = {
'input_string': egs.Required(str),
'input_integer': int,
},
output_format = {
'output_string': str,
'output_integer': int,
},
method = lambda input_string, input_integer=None: {
'output_string': 2 * input_string,
'output_integer': None if input_integer is None else 2 * input_integer,
},
)
_internal_value = 0
def bar_mutation_method(value=None, increment_value=None):
if value is not None:
_internal_value = value
if increment_value is not None:
_internal_value += increment_value
return {
'value': _internal_value,
}
schema.expose_mutation(
name = 'bar',
input_format = {
'input_string': egs.Required(str),
'input_integer': int,
},
output_format = {
'output_string': str,
'output_integer': int,
},
method = bar_mutation_method,
)
Subclassing Schema.ExposedQuery
and Schema.ExposedMutation
import easy_graphql_server as egs
schema = egs.Schema()
class FooQuery(schema.ExposedQuery):
name = 'foo'
input_format = {
'input_string': egs.Required(str),
'input_integer': int,
}
output_format = {
'output_string': str,
'output_integer': int,
}
@staticmethod
def method(input_string, input_integer=None):
return {
'output_string': 2 * input_string,
'output_integer': None if input_integer is None else 2 * input_integer,
}
class BarMutation(schema.ExposedMutation):
name = 'bar'
_internal_value = 0
input_format = {
'value': int,
'increment_value': int,
}
output_format = {
'value': int,
}
@classmethod
def method(cls, value=None, increment_value=None):
if value is not None:
cls._internal_value = value
if increment_value is not None:
cls._internal_value += increment_value
return {
'value': cls._internal_value,
}
Subclassing easy_graphql_server.ExposedQuery
and easy_graphql_server.ExposedMutation
This is very similar to the previous way.
import easy_graphql_server as egs
class FooQuery(schema.ExposedQuery):
name = 'foo'
input_format = {
'input_string': egs.Required(str),
'input_integer': int,
}
output_format = {
'output_string': str,
'output_integer': int,
}
@staticmethod
def method(input_string, input_integer=None):
return {
'output_string': 2 * input_string,
'output_integer': None if input_integer is None else 2 * input_integer,
}
class BarMutation(schema.ExposedMutation):
name = 'bar'
_internal_value = 0
input_format = {
'value': int,
'increment_value': int,
}
output_format = {
'value': int,
}
@classmethod
def method(cls, value=None, increment_value=None):
if value is not None:
cls._internal_value = value
if increment_value is not None:
cls._internal_value += increment_value
return {
'value': cls._internal_value,
}
schema = egs.Schema()
schema.expose(FooQuery)
schema.expose(BarMutation)
Available options for exposing methods
The same options can be passed either as class attributes for subclasses of Schema.ExposedQuery
and Schema.ExposedMutation
, or as keyword arguments to Schema.expose_query()
and Schema.expose_mutation()
methods.
Options for queries and mutations are the same.
-
name
is the name under which the method shall be exposed -
method
is the callback function of your choice -
input_format
is the input format for the GraphQL method, passed as a (possibly recursive) mapping; if unspecified orNone
, the defined GraphQL method will take no input; the mapping keys are -
output_format
is the output format of the GraphQL method, passed as a (possibly recursive) mapping or as alist
containing one mapping -
pass_graphql_selection
can either be abool
or astr
; if set toTrue
, thegraphql_selection
parameter will be passed to the callback method, indicating which fields are requested for output; if set to astr
, the given string will be the name of the keyword parameter passed to the callback method instead ofgraphql_selection
-
pass_graphql_path
can either be abool
or astr
; if set toTrue
, thegraphql_path
parameter will be passed to the callback method, indicating as alist[str]
the GraphQL path in which the method is being executed; if set to astr
, the given string will be the name of the keyword parameter passed to the callback method instead ofgraphql_path
-
pass_authenticated_user
can either be abool
or astr
; if set toTrue
, theauthenticated_user
parameter will be passed to the callback method, indicating the user authenticated in the source HTTP request (orNone
if the request was unauthenticated); if set to astr
, the given string will be the name of the keyword parameter passed to the callback method instead ofauthenticated_user
-
require_authenticated_user
is abool
indicating whether or not authentication is required for the exposed method
Expose ORM models
What does it do?
For instance, exposing a model called Thing
will expose the following queries...
thing
: fetch a single instance of the model given its unique identifierthings
: fetch a collection of model instances, given filtering criteria, or unfiltered, paginated or not
...and mutations:
create_thing
: create a single instance of the model given the data to be insertedupdate_thing
: update a single instance of the model given its unique identifier and a mapping the new data to applydelete_thing
: delete a single instance of the model given its unique identifier
Calling Schema.expose_model()
import easy_graphql_server
from my_django_application.models import Person
schema = easy_graphql_server.Schema()
schema.expose_model(
orm_model=Person,
plural_name='people',
can_expose=('id', 'first_name', 'last_name'),
cannot_write=('id',),
)
Subclassing Schema.ExposedModel
import easy_graphql_server
from my_django_application.models import Person
schema = easy_graphql_server.Schema()
class ExposedPerson(schema.ExposedModel):
orm_model = Person
plural_name = 'people'
can_expose = ('id', 'first_name', 'last_name')
cannot_write = ('id',)
Subclassing easy_graphql_server.ExposedModel
This is very similar to the previous way.
import easy_graphql_server
from my_django_application.models import Person
schema = easy_graphql_server.Schema()
class ExposedPerson(easy_graphql_server.ExposedModel):
orm_model = Person
plural_name = 'people'
can_expose = ('id', 'first_name', 'last_name')
cannot_write = ('id',)
schema = easy_graphql_server.Schema()
schema.expose(ExposedPerson)
Available options for exposing models
The same options can be passed either as class attributes for subclasses of ExposedModel
, or as keyword arguments to Schema.expose_model()
method.
-
cannot_expose
is either abool
, or atuple[str]
; defaults toFalse
; if set toTrue
, no query or mutation method will be exposed for the model; if set to a list of field names, those fields will be excluded from every query and mutation -
can_create
is either abool
, or atuple[str]
; defaults toTrue
; if set toFalse
, no creation mutation method will be exposed for the model; if set to a list of field names, only those fields will be possible field values passed at insertion time tocreate_...
-
cannot_create
is either abool
, or atuple[str]
; defaults toFalse
; if set toTrue
, no creation mutation method will be exposed for the model; if set to a list of field names, those fields will be excluded from possible field values passed at insertion time tocreate_...
-
can_read
is either abool
, or atuple[str]
; defaults toTrue
; if set toFalse
, no query method will be exposed for the model; if set to a list of field names, only those fields will be exposed for the...
(show one instance) and...s
(show a collection of instances) queries (it also defines which fields are available as mutations results) -
cannot_read
is either abool
, or atuple[str]
; defaults toFalse
; if set toTrue
, no query method will be exposed for the model; if set to a list of field names, only those fields will be exposed for the...
(show one instance) and...s
(show a collection of instances) queries (it also defines which fields are not available as mutations results) -
can_update
is either abool
, or atuple[str]
; defaults toTrue
; if set toTrue
, nodelete_...
mutation method will be exposed for the model; if set to a list of field names, those fields will be the only possible keys for the_
parameter (new data for instance fields) of theupdate_...
mutation -
cannot_update
is either abool
, or atuple[str]
; defaults toFalse
; if set toTrue
, noupdate_...
mutation method will be exposed for the model; if set to a list of field names, those fields will be excluded from possible keys for the_
parameter (new data for instance fields) of theupdate_...
mutation -
can_delete
is abool
; defaults toTrue
; if set toFalse
, nodelete_...
mutation method will be exposed for the model -
cannot_delete
is abool
; defaults toFalse
; if set toTrue
, nodelete_...
mutation method will be exposed for the model -
only_when_child_of
is eitherNone
(model does not have to be nested to be exposed),True
(the model is not exposed if not nested), an ORM model class, or a tuple/list/set of ORM model classes (the defined model can only be exposed when nested directly under one of models passed asonly_when_child_of
parameter) -
require_authenticated_user
is abool
indicating whether or not authentication is required for the exposed method -
has_permission
is eitherNone
, or a callback method returning abool
(True
if operation is authorized,False
otherwise), and taking as parametersauthenticated_user
(self-explanatory),operation
(a value of theeasy_graphql_server.Operation
enum:CREATE
,READ
,UPDATE
orDELETE
) anddata
(new data, only applies toCREATE
andUPDATE
) -
filter_for_user
is eitherNone
, or a callback method returning aqueryset
, and taking as parametersqueryset
andauthenticated_user
Perform GraphQL queries
If you want to perform GraphQL queries on the schema without going through a schema, you can use Schema.execute()
. This method can take the following parameters:
query
: the GraphQL query, in the form of astr
variables
: variables to go along with the query (optional), as adict[str,Any]
operation_name
: name of the operation to be executed within the query (optional)authenticated_user
: parameter that will be passed to the callback functions of GraphQL methods that require it (optional)serializable_output
: the output will be rendered as JSON-serializabledict
, instead of agraphql.execution.execute.ExecutionResult
instance
Credits and history
The easy_graphql_server library was originally a subproject within the Bridger development team, to provide an easy way to expose database models with GraphQL using Graphene.
The project was then rewritten with graphq-core and Graphene was dropped.
License
easy_graphql_server is under MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for easy_graphql_server-0.9.31.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | da6302487e6ac1d5a094c361eb9c31de5bee7a0f21f883494501828d37fc61ac |
|
MD5 | 62387fad534f3f44b6e588e2db6d905b |
|
BLAKE2b-256 | 77e5d50d9c25c77d2b3368f5c35c8dcff0e0905e70166bacbab21c0ccc97d6db |
Hashes for easy_graphql_server-0.9.31-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d3b72f66cdd30d6204e25d601f89b6ad0df061e04623aacd5259517a0cbd13d8 |
|
MD5 | fad3951cebe0eda9b4375aebde6ac86b |
|
BLAKE2b-256 | 42252b79d4f56748505c4397b6756c2404d9c961065848c083684eb90701cb4d |