Graphy - a demo of Graphene-Django
Parts of the documentation of Graphene is currently a bit slim. The purpose of this repository is to show code examples compared against DRF, and help getting started with GraphQL on a Django backend, or transitioning from DRF.
- Transition from DRF is surprisingly easy, and is done in quite few lines of code.
- Documentation from Django
help_textwill be reused in schema generated from GraphQL.
- You can reuse existing DRF serializers and validation
- Addressing authentication and authorization is not a part of GraphQL spec and there's little help in Graphene or documentation about it. Own implementation can be found at graphy/utils/graphql.py
- Graphene performs comparably to DRF even if you have "ideal" REST endpoints that avoid overfetching.
- 3d55467 - Adding your first GraphQL endpoint and query.
- c71967a - Adding your first GraphQL test.
- e7a366c - Reusing DRF serializer to create your first mutation.
- 3a72f29 -
@auth_requiredwrapper added, returning a HTTP 401 or error object (Two different views).
- ece2cf0 - Disallowing queries over a given depth.
Since the nature of GraphQL and REST APIs are quite different, a performance comparision might not map to the differences in your real life situation.
While it makes perfect sense to prefetch (
select_related with Django ORM)
to a REST endpoint that needs the prefetched data, the same can not be said for
GraphQL endpoints, since a signle GraphQL Query (or "endpoint" if you talk REST)
can be used for different cases.
For an ideal implmentation (performance wise), where a Graphene Query and a
DRF endpoint is implemented to serve a single, given data request, it
looks like DRF is performing better: 1-5% when the
not used, and 10-50% when
select_related is used. The relative difference
seems to to be larger the more instances are returned.
For real life implementations, overfetching is a problem that GraphQL
avoids to a much larger degree than REST, and we've seen (large)
performance gains at Otovo when switching from
DRF to GraphQL. But be aware that GraphQL list queries where nested models
are fetched can be slow when using Graphene naively. Consider adding
own endpoints using
select_related for such queris, or implementing
assistance that modifies the database query based on the GraphQL Query.
Details of tests can be found in
./graphy/location/tests/test_gql_vs_drf_performance.py(GraphQL Query / REST call)
Numbers below are an average of 500 requests done when using curl against a non-debug server running postgres.
|Type||Avg time||Returned objects|
|Shallow GraphQL query||19.2 ms||1|
|Deep GraphQL query||28.1 ms||1|
|Shallow GraphQL query||29.8 ms||100|
|Deep GraphQL query||441.6 ms||100|
|Type||Avg time||Returned objects|
|Shallow GraphQL query||22.8 ms||1|
|Deep GraphQL query||26.2 ms||1|
|Shallow GraphQL query||49.9 ms||100|
|Deep GraphQL query||75.54 ms||100|
This repo should work out of the box with python 3.7, and probably most other python 3 versions.
The commands below install 3.7 specifically on Mac / Linux
# See https://github.com/pyenv/pyenv-installer if you got Linux brew install pyenv # Installs 3.7.0, specified in .python-version pyenv install
# Create and activate virtualenv $(pyenv which python) -m venv .venv source .venv/bin/activate pip install -r requirements.txt
Load test data
python manage.py migrate python manage.py loaddata db.json
This db dump includes a few instances of each model and a superuser
admin and password
python manage.py migrate python manage.py runserver
Admin panel runs at
localhost:8000/admin. If you need to, you can
create a super user with
python manage.py createsuperuser
Interactive GraphiQL runs at localhost:8000/graphql.
# Runs all tests pytest