All Ruby on Rails Node JS Android iOS React Native Frontend

A Brief Introduction to GraphQL in Django

What is graphQL?

GraphQL is an open source data query and manipulation language. It was created by Facebook in 2012 and publicly released in 2015.

Repository of graphQL: https://github.com/facebook/graphql

It is often described as an alternative to the REST approach.

Some people say that graphQL is not yet production ready compared to the REST.

Comparison of graphQL and REST: https://blog.apollographql.com/graphql-vs-rest-5d425123e34b

While other recommend that migration to graphQL can be easily done and will not bring any huge problems: https://0x2a.sh/from-rest-to-graphql-b4e95e94c26b

On PyCode conference in Warsaw I did lightning talk about graphQL. I asked how many people ever heard of it, out of 40 people about half of them did, but only 2 of the audience members ever used it, none of them in production.

Since it is developed by facebook I’ve seen heavy marketing of graphQL in React community. But none of frontend developers I know is using it right now.

Main features

  • Sending multiple queries in one request

  • Query defines what data should be defined

  • Only one endpoint handles all requests

Examples

Types

All graphQL operations rely on predefined types. It is a definition on how the model would look like, what fields, filters it supports.

 

type Human {
  id: String
  name: String
  homePlanet: String
}

Query

When we have type we can start to query. For example we need to get all types of Humans but we want to have only their names.

{
  hero {
    name
  }
}

We can also have queries with arguments

{
  human(id: "1000") {
    name
  }
}

Since there are also mutations we might need to include query keyword and name of the operation.

query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}

In this example we also see that hero object has related objects called friends, we can also include them if we want. Queries can also have variables and directives (include and skip) which might be useful from frontend point of view. More can be found on official documentation: http://graphql.github.io/learn/queries/

Mutations

They allow us to create/update objects. While query fields are executed in parallel, mutation fields run in series, one after the other.

Create review example that uses variables:

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

Python

We can use graphQL in Python with graphene package.

Documentation can be found here: https://docs.graphene-python.org/en/latest/

It can be used in Django in similar way Django REST Framework works.

Django

Quick show of how graphene can be used in Django:

https://medium.com/@jamesvaresamuel/mutation-and-query-in-graphql-using-python-django-part-2-79d9852a1092

More detailed tutorial: https://www.howtographql.com/graphql-python/1-getting-started/

Examples

Models

They stay the same as they were done before. Database type does not matter. GraphQL is often mistaken as a SQL/database language or even database itself. It is not either of them.

Model can look like this:

class Movie(models.Model):
    title = models.CharField(max_length=128)
    year = models.IntegerField(blank=True)

Types

As mentioned before graphQL operates on types. Most simple type for previous model can look like this:

class MovieType(DjangoObjectType):
    class Meta:
        model = Movie

We can also include extra type of data which can allow us to add for example filtering.

class MovieType(DjangoObjectType):
    class Meta:
        model = Movie
        filter_fields = {
            'title': ['exact', 'icontains', 'istartswith'],
            'genre': ['exact', 'icontains'],
            'year': ['exact'],
        }

For filtering graphene is using django-filter package which needs to be installed separately.

Queries

Before we can start sending requests we need to define queries that can be done.

class MovieQuery(object):
    all_movies = graphene.List(MovieType)
    def resolve_all_movies(self, info, **kwargs):
       return Movie.objects.all()

Such Query will allow us to execute following query in request.

{
  all_movies {
    title
  }
}

We can easily extend that Query to get other cases, for example single movie or one with specific year:

class MovieQuery(object):
    movie = graphene.Field(
        MovieType,
        id=graphene.String(),
        title=graphene.String()
    )
    all_movies = graphene.List(MovieType)

    def resolve_movie(self, info, **kwargs):
        id = kwargs.get('id')
        title = kwargs.get('title')

        if id is not None:
            return Movie.objects.get(pk=id)

        if title is not None:
            return Movie.objects.get(title=title)

        return None

    def resolve_all_movies(self, info, **kwargs):
        return Movie.objects.all()

Mutations

Creating Mutations is similar to the queries.

class CreateMovie(graphene.Mutation):
    class Arguments:
        title = graphene.String(required=True)
        year = graphene.Int(required=False)

    movie = graphene.Field(lambda: MovieType)

    def mutate(self, info, title, year=None):
        new_movie = Movie.objects.create(title=title, year=year)
        return CreateMovie(movie=new_movie)

 Mutation itself defines fields that are required when we want to create object. It also needs to define mutate method.

class MovieMutation(graphene.ObjectType):
    create_movie = CreateMovie.Field()

 Finally we need to create graphene object so we could later point it to the application schema.

URL and Schema

To make previous examples be available in project we need to complete schema for graphene and set up url.

Setting up schema for queries and mutations:

schema = graphene.Schema(query=MovieQuery, mutation=MovieMutation)

URL pattern for graphene:

url(r'^graphql', GraphQLView.as_view(graphiql=True)),

Graphiql is a visual tool that allows us to browse the allowed queries/mutations and types like an interactive documentation and to execute graphQL code.

Summary

graphQL can surely be seen as an alternative to REST, but it is still not that popular.

Pros:

  • Simplified development on backend side, many parts of code are not needed as they were in DRF, like serializers and views

  • Only one endpoint

  • More freedom on frontend part, no need for new views that include/exclude specific field

  • Multiple queries in one request

Cons:

  • Only one endpoint can be confusing

  • It is a new language for querying that needs to be learn

  • Caching can be currently done only on frontend part of the application

  • No benchmarks/performance comparisons available yet

Example application

I have created example of graphene use in Django. Project can be found here: https://github.com/krzyszti/graphene_example

featured photo by: https://unsplash.com/@ikukevk

We're building our future. Let's do this right - join us
New Call-to-action
READ ALSO FROM Python
Read also
Need a successful project?
Estimate project or contact us