GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.
#Set up the Django project
We will set up the project, create the following:
- A Django project called cookbook
- An app within cookbook called ingredients
# Create the project directory
mkdir cookbook
cd cookbook
# Create a virtualenv to isolate our package dependencies locally
virtualenv env
source env/bin/activate # On Windows use `env\Scripts\activate`
# Install Django and Graphene with Django support
pip install django
pip install graphene_django
# Set up a new project with a single application
django-admin.py startproject cookbook . # Note the trailing '.' character
cd cookbook
django-admin.py startapp ingredients
Now sync your database for the first time:
python manage.py migrate
Let’s create a few simple models…
###Defining our models
Let’s get started with these models:
# cookbook/ingredients/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(max_length=100)
notes = models.TextField()
category = models.ForeignKey(
Category, related_name='ingredients', on_delete=models.CASCADE)
def __str__(self):
return self.name
Add ingredients as INSTALLED_APPS:
INSTALLED_APPS = [
...
# Install the ingredients app
'cookbook.ingredients',
]
Don’t forget to create & run migrations:
python manage.py makemigrations
python manage.py migrate
###Load some test data
Now is a good time to load up some test data. The easiest option will be to download the ingredients.json fixture and place it in cookbook/ingredients/fixtures/ingredients.json
.You can then run the following:
$ python ./manage.py loaddata ingredients
Installed 6 object(s) from 1 fixture(s)
Alternatively you can use the Django admin interface to create some data yourself. You’ll need to run the development server (see below), and create a login for yourself too (./manage.py createsuperuser)
.
Register models with admin panel:
# cookbook/ingredients/admin.py
from django.contrib import admin
from cookbook.ingredients.models import Category, Ingredient
admin.site.register(Category)
admin.site.register(Ingredient)
#Hello GraphQL - Schema and Object Types
In order to make queries to our Django project, we are going to need few things:
- Schema with defined object types
- A view, taking queries as input and returning the result
GraphQL presents your objects to the world as a graph structure rather than a more hierarchical structure to which you may be accustomed. In order to create this representation, Graphene needs to know about each type of object which will appear in the graph.
This graph also has a root type through which all access begins. This is the Query
class below.
This means, for each of our models, we are going to create a type, subclassing DjangoObjectType
After we’ve done that, we will list those types as fields in the Query
class.
Create cookbook/ingredients/schema.py
and type the following:
# cookbook/ingredients/schema.py
import graphene
from graphene_django.types import DjangoObjectType
from cookbook.ingredients.models import Category, Ingredient
class CategoryType(DjangoObjectType):
class Meta:
model = Category
class IngredientType(DjangoObjectType):
class Meta:
model = Ingredient
class Query(object):
all_categories = graphene.List(CategoryType)
all_ingredients = graphene.List(IngredientType)
def resolve_all_categories(self, info, **kwargs):
return Category.objects.all()
def resolve_all_ingredients(self, info, **kwargs):
# We can easily optimize query count in the resolve method
return Ingredient.objects.select_related('category').all()
Note that the above Query
class is a mixin, inheriting from object. This is because we will now create a project-level query class which will combine all our app-level mixins.
Create the parent project-level cookbook/schema.py
:
import graphene
import cookbook.ingredients.schema
class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
# This class will inherit from multiple Queries
# as we begin to add more apps to our project
pass
schema = graphene.Schema(query=Query)
You can think of this as being something like your top-level urls.py
file (although it currently lacks any namespacing).
#Update settings
Next, install your app and GraphiQL in your Django project. GraphiQL is a web-based integrated development environment to assist in the writing and executing of GraphQL queries. It will provide us with a simple and easy way of testing our cookbook project.
Add graphene_django
to INSTALLED_APPS
in cookbook/settings.py
:
INSTALLED_APPS = [
...
# This will also make the `graphql_schema` management command available
'graphene_django',
]
And then add the SCHEMA
to the GRAPHENE
config in cookbook/settings.py
:
GRAPHENE = {
'SCHEMA': 'cookbook.schema.schema'
}
#Creating GraphQL and GraphiQL views
Unlike a RESTful API, there is only a single URL from which GraphQL is accessed. Requests to this URL are handled by Graphene’s GraphQLView
view.
This view will serve as GraphQL endpoint. As we want to have the aforementioned GraphiQL we specify that on the parameters with graphiql=True
.
from django.conf.urls import url, include
from django.contrib import admin
from graphene_django.views import GraphQLView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^graphql', GraphQLView.as_view(graphiql=True)),
]
If we didn’t specify the target schema in the Django settings file as explained above, we can do so here using:
#Testing our GraphQL schema
We’re now ready to test the API we’ve built. Let’s fire up the server from the command line.
$ python ./manage.py runserver
Performing system checks...
Django version 1.9, using settings 'cookbook.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Go to localhost:8000/graphql and type your first query!
query {
allIngredients {
id
name
}
}
If you are using the provided fixtures, you will see the following response:
{
"data": {
"allIngredients": [
{
"id": "1",
"name": "Eggs"
},
{
"id": "2",
"name": "Milk"
},
{
"id": "3",
"name": "Beef"
},
{
"id": "4",
"name": "Chicken"
}
]
}
}
#Summary
GraphQL is very powerful. In the next article I will create the frontend side to query all the data from backend using React.