Create GraphQL API
In the first part, we created the Django project with item app that includes our movie model. This second and third parts of the article is supported not financially but morally by LA-CUISINETTE Vegan Foods.
In this part, we will create a simple API with GraphQL that will response queries that requested from our client-side app.
Here the links of all parts of this tutorial:
Step-1: Create an API app
Let's create our second app that will be responsible for GraphQL API.
# djr/
# create app with the name gql
# (name is not necessarily to be gql)
python manage.py startapp gql
Step-2: Configure Url endpoints and necessary settings
Add URL endpoint that all the API requests will be done through.
Note: (graphiql=True) option is responsible for interactive GraphQL API browser. We will use it for manually querying the database.
from django.contrib import admin
from django.urls import path
from graphene_django.views import GraphQLView
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
# apiclient on client-side will request this adress later
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
# index.html file will be our root template. When a user opens our webste,
# this file will be sent by server at first. After then, api requests
# will directed above address.
# (it points to ~/Blog/djr/templates/index.html)
# (currently there is no file, webpack production bundle will come here )
path("", TemplateView.as_view(template_name="index.html")),
]
Define the schema location for Graphene in the settings.py file of your Django project. SCHEMA location points to our schema that we will create in a moment.
# djr/djr/settings.py
GRAPHENE = {
'SCHEMA': 'gql.schema.schema'
}
Create a schema.py file in gql directory.
# djr/gql/schema.py
import graphene
# this is what we define SCHEMA in settings.py
schema = graphene.Schema(query=Query)
Step-3: Define API model and query
Now, we should clearly define the API requests and its relevant type of data.
First, we will create an API model type and its resolvers that will be the interface of our previously defined movie model.
You can also define custom types with graphene.ObjectType that is not connected to any pre-defined django-model.
API-Model
When we create API-model, we first define API-model-fields with respect to our original movie model. There is no obligation to define all the field, but we will do. Also, you can write custom fields that are not defined before.
Let's look at how our movie model fields and API-model fields are paired.
Resolvers
After the fields, we will define resolvers which are responsible for the logic part. The second argument of resolvers is info argument which holds useful information like authentication or HTTP information.
Queries
Now we are going to write our queries. Client-side app will make their requests according to these queries. For the sake of simplicity, only two queries will be defined.
The movie_list query returns all the movies in the database.
The movie query returns only specific movie if slug of the URL matches any slug field of a movie.
The final code of schema.py file is here:
import graphene
from items.models import Movie
from graphene_django.types import DjangoObjectType
# api-movie-model
class MovieType(DjangoObjectType):
id = graphene.Int()
name = graphene.String()
year = graphene.Int()
summary = graphene.String()
poster_url = graphene.String()
slug = graphene.String()
class Meta:
model = Movie
def resolve_id(self, info):
return self.id
def resolve_name(self, info):
return self.name
def resolve_year(self, info):
return self.year
def resolve_summary(self, info):
return self.summary
def resolve_poster_url(self, info):
# Note: in client side app snake_case fields
# will be resolved as camelCase
# Eg: poster_url ==> posterUrl
return self.poster_url
def resolve_slug(self, info):
return self.slug
class Query(graphene.ObjectType):
movie_list = graphene.List(MovieType)
movie = graphene.Field(MovieType, slug=graphene.String())
def resolve_movie_list(self, info, *_):
# for large lists only query what you need
return Movie.objects.all().only("name", "poster_url", "slug")
def resolve_movie(self, info, slug):
movie_queryset = Movie.objects.filter(slug=slug)
if movie_queryset.exists():
return movie_queryset.first()
schema = graphene.Schema(query=Query)
Writing API for backend is finished. Now, we can check it in the GraphQL interactive browser.
Step-3: Interactive GraphQL playground
Please run the server and open http://127.0.0.1:8000/graphql in the browser and write this. You will see the response to this query.
query {
#the query name
movieList{
# the fields which we will request
id,
name,
posterUrl, #camelCase
}
}
Our second query has arguments. We can make the request like this:
query {
#the query and argument
movie(slug:"the-matrix-1999"){
# the fields which we will request
id,
name,
posterUrl, #camelCase
}
}
then the response will be:
{
"data": {
"movie": {
"id": 2571,
"name": "The Matrix",
"posterUrl": "<https://image.tmdb.org/t/p/w185/lZpWprJqbIFpEV5uoHfoK0KCnTW.jpg>"
}
}
}
We checked that our API is ready.This part of the tutorial is finished. You can stop the server.
Next, we will create a single page application with React. Then we make requests to our backend.