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
File details
Details for the file easy_graphql_server-0.9.3.tar.gz
.
File metadata
- Download URL: easy_graphql_server-0.9.3.tar.gz
- Upload date:
- Size: 39.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/34.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.9 tqdm/4.63.1 importlib-metadata/4.11.3 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ea0f5ff73be0021b9376753dc84054590918eb94ba0a93c942ba82730e2bc532 |
|
MD5 | d1be2fb47ffcb62814b9062b86845351 |
|
BLAKE2b-256 | a2257ef3d68617e60329ea747c07f5336ee27f3c19039dfc743bdf8eb860bb5b |
File details
Details for the file easy_graphql_server-0.9.3-py3-none-any.whl
.
File metadata
- Download URL: easy_graphql_server-0.9.3-py3-none-any.whl
- Upload date:
- Size: 45.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/34.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.9 tqdm/4.63.1 importlib-metadata/4.11.3 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ca0efbc30c049e653f62b5001f77848e77b5dc001b31194222188c9413b0ef1d |
|
MD5 | 3505d95e519aa20395c08a72b64ae3a3 |
|
BLAKE2b-256 | 54e47f89027d6621b77c7d7bb74c8a929ea1493fb1690610f641fc978589a8a7 |