Quickly experience GraphQL with graphene and Django

Rain Wu
Random Life Journal
5 min readSep 15, 2020

--

During my search for job opportunities in the past few weeks, I found that the frequency of the keyword “GraphQL” appears in the description of vacancies has become much higher than last year. Although I am an engineer accustomed to REST, my strong curiosity still drives me to give it a try.

There are several modules that can help us implement GraphQL API, I have no special consideration now, so I just pick the most popular one. graphene-django would be great for a quick start, it has plenty of discussion on the internet and highly-integrated with the Django framework.

The Pain of REST

Representational State Transfer (REST) is an architectural approach or concept that base on resources, which means all the interaction should be resource-oriented. But this practice starts to cause some problems in modern complex services:

Under-fetching

Basically, the endpoint of the Restful API represents a specific resource, the client-side is almost impossible to access multiple resources within a single request.

For example, get the commodities and the announcements on the bulletin board at the same time for rendering the homepage, two requests are needed.

GET    /commodities
GET /announcements

There’s a lot of similar situation require more than one request, even if we know what we need at the beginning. The defect of inefficient will dramatically enlarge as long as your resources and users grow continuously, but we are still at a loss for too many requests.

Over-fetching

Most of the time while we tend to access a resource, we do not need all the fields. As far as a recommended list is concerned, we only need the image, name, and price of the commodities, but an integral commodity resource may also contain a timestamp, description, and inventory.

{
"image": "xxx."
"name": "vacuum cleaner"
"price": 150,
"timestamp": "2020-09-11 17:31:52"
"description": "cheap vacuum cleaner for sale!"
"inventory": 4
}

Unused fields will cause unnecessary transmission load on the server, especially when the resource contains heavy content or lots of embedded resources.

Specify which field we actually need can improve directly, the server can construct the response via resolving the query string and get rid of the limit of resource-based principles. Meanwhile, it would be more convenient to records detailed usage of each field for data engineering and requirements analyzing.

Here comes GraphQL

GraphQL’s superior flexibility and scalability lead a clear path, the concept of Schema, Query, and Mutation strike a great balance between under-fetching and over-fetching. As a query language, the client-side can construct a more-customized request, and so does the response from the server-side.

But the learning curve is also steeper, a well-designed resolver needs to consider more comprehensive operational requirements, not just the operating options of a resource like REST.

GraphQL is not a replacement for REST, resource-based APIs still have obvious advantages in maintainability and readability. These two approach methods can coexist in the same service, and they can be used alternately depending on the situation.

Project Set up

First, we start a python project with poetry and install the package django-graphene.

$ poetry init
$ poetry add graphene-django
$ poetry run django-admin startproject warship

Also, append graphene to INSTALLED_APPS in the settings.py.

Next, define the schema inside schema.py, and specified it for graphene.

Last, update the URL rules.

Run the server at local and visit http://127.0.0.1:8000/graphql you will see the GUI of graphene. I’m using the native dark theme of Chrome, so maybe your background color will be different from mine.

Now we can test it with the corresponding query structure:

query{
name
}

The expected response should be:

{
"data": {
"name": "ID: MyShip"
}
}

Extend the Schema

In fact, the resource structure is definitely not as simple as the example above, graphene also supports several ways to construct advanced schema. The common field can be defined by the class graphene.Interface, similar to the interface concept with OOP.

However, this abstract layer can not be instantiated. Another practical class is needed to inherit the interface in subclass Meta, it also allows us to derivative new fields for each different model.

In order to facilitate the test, I create some data instances and assign it to the attributes of the query object. This time we use two types of field resolvers to handle different query requests in different conditions, List field can respond with a list of objects, and the common field is for a single one.

Most of the time in a launched service, the data should be stored in the databases or some warehousing tools. But the workflow is almost the same: resolve, access data, and return them.

Here we can enjoy the powerful feature of GraphQL, request for multiple resources, and specified which field is necessary within only one request.

{
name
cost
turrets(slots: [2, 4, 5]) {
name
durability
}
cabins(positions: [1, 3]) {
name
power_consumption
}
observatory(name: "O-01") {
name
power_consumption
view_distance
}
}

The expected response should contain a turret list, a cabin list, and an observatory with the name “O-01”.

{
"data": {
"name": "ID: MyShip",
"cost": 230,
"turrets": [
{
"name": "CANNON-013",
"durability": 86
},
{
"name": "ROCKET-021",
"durability": 300
},
{
"name": "ROCKET-029",
"durability": 197
}
],
"cabins": [
{
"name": "O-02",
"power_consumption": 30
},
{
"name": "O-02",
"power_consumption": 80
}
],
"observatory": {
"name": "O-01",
"view_distance": 300
}
}
}

As far as a backend engineer who familiar with REST was concerned, this kind of response is extremely incomprehensible and could be doubted at the stage of API design.

Conclusion

Obviously, the concept of GraphQL is really a solution for the issue of data fetching, more and more companies take it as a must-have qualification.
Although there will be inevitable inadaptability in planning and implementation, it is still worth learning to deal with complex resource structures.

--

--

Rain Wu
Random Life Journal

A software engineer specializing in distributed systems and cloud services, desire to realize various imaginations of future life through technology.