GraphQL and Django in 5 minutes

August 5, 2017

TL;DR Jump to the coding part or get the code here.

What is GraphQL?

GraphQL query is a string that is sent to a server to be interpreted and fulfilled, which then returns JSON back to the client. It was created by Facebook in 2012 and the first specification draft was made public in 2015.

In this tutorial I will cover the basics of working with GraphQL and Django.

Getting started

Before creating the project and all, make sure you have virtualenv installed, so that the packages used in this tutorial won’t be installed system-wide.

# Clone the repo git clone https://github.com/joaorafaelm/graphql-django-example ; cd graphql-django-example ; # Create virtualenv virtualenv venv && source venv/bin/activate ; # Install django and graphene pip install -r requirements.txt ; # Setup db python manage.py migrate ;

Run python manage.py loaddata books.json to populate the db, or run python manage.py createsuperuser and then add some data using the admin interface.

Models and GraphQL Schema

This example is going to use the models Author, Book and Publisher.

# bookstore/store/models.py from django.db import models class Publisher ( models . Model ): name = models . CharField ( max_length = 30 ) website = models . URLField () def __str__ ( self ): return self . name class Author ( models . Model ): first_name = models . CharField ( max_length = 30 ) last_name = models . CharField ( max_length = 40 ) email = models . EmailField () def __str__ ( self ): return ' % s % s' % ( self . first_name , self . last_name ) class Book ( models . Model ): title = models . CharField ( max_length = 100 ) authors = models . ManyToManyField ( Author ) publisher = models . ForeignKey ( Publisher ) publication_date = models . DateField () def __str__ ( self ): return self . title

After creating the models, the Schema should be created, which will be used to serve the API.

At the time of writing this post, graphene-django version is 1.3 and it does not handle ManyToMany fields properly, that is why the resolve_authors method was added. This issue has been resolved for the next release.

# bookstore/schema.py import graphene from graphene_django.types import DjangoObjectType from graphene_django.debug import DjangoDebug from bookstore.store.models import Author , Book , Publisher class AuthorType ( DjangoObjectType ): class Meta : model = Author class BookType ( DjangoObjectType ): authors = graphene . List ( AuthorType ) # Many To Many fix until next release. # https://github.com/graphql-python/graphene-django/issues/155 @ graphene . resolve_only_args def resolve_authors ( self ): return self . authors . all () class Meta : model = Book class PublisherType ( DjangoObjectType ): class Meta : model = Publisher class Query ( graphene . ObjectType ): all_authors = graphene . List ( AuthorType ) all_books = graphene . List ( BookType ) all_publishers = graphene . List ( PublisherType ) # Debug field (rawSql, parameters etc). debug = graphene . Field ( DjangoDebug , name = '__debug' ) def resolve_all_authors ( self , args , context , info ): return Author . objects . all () def resolve_all_books ( self , args , context , info ): return Book . objects . select_related ( 'publisher' ) . all () def resolve_all_publishers ( self , args , context , info ): return Publisher . objects . all () schema = graphene . Schema ( query = Query )

Last but not least, the GraphQL URL must be added into the urls.py file.

# bookstore/urls.py from django.conf.urls import url from django.contrib import admin from graphene_django.views import GraphQLView from bookstore.schema import schema urlpatterns = [ url ( r'^admin/' , admin . site . urls ), url ( r'^graphql' , GraphQLView . as_view ( graphiql = True , schema = schema )), ]

You can now run python manage.py runserver and start using the API at http://localhost:8000/graphql.

Querying and debugging

GraphiQL provides a graphical interactive in-browser GraphQL IDE, including some features such as syntax highlighting, real-time error reporting, automatic query completion etc.

I will show some query examples, but you can learn more about querying at graphql.org/learn/queries/.

Given the following query, we can retrieve all books registered along with their authors.

{ allBooks { title , authors { firstName , lastName } } }

And the response…

{ "data" : { "allBooks" : [ { "title" : "Resurrection" , "authors" : [ { "firstName" : "Leo" , "lastName" : "Tolstoy" } ] }, { "title" : "Childhood" , "authors" : [ { "firstName" : "Leo" , "lastName" : "Tolstoy" } ] } ] } }

Using the __debug field you can get information about the actual SQL query.

{ allAuthors { lastName } __debug { sql { rawSql , duration } } }

Response:

{ "data" : { "allAuthors" : [ { "lastName" : "King" }, { "lastName" : "Tolstoy" }, { "lastName" : "Gaiman" }, { "lastName" : "Pratchett" } ], "__debug" : { "sql" : [ { "rawSql" : "SELECT \" store_author \" . \" id \" , \" store_author \" . \" first_name \" , \" store_author \" . \" last_name \" , \" store_author \" . \" email \" FROM \" store_author \" " , "duration" : 0.0009260177612304688 } ] } } }

All this code is on my Github. Please do fork it and make pull requests regarding any issues or improvements you may have with my code.