Hello GraphQL :A Practical Guide

Hatembentayeb
6 min readNov 30, 2019

--

In this article i will go through an alternative tool for the REST API which is GRAPHQL . we will begin by introducing the core concept , comparing these two tools and we will finish by implementing an example using python programming language.

What is GraphQL ?

GraphQl is an alternative to rest api so … so what is the difference ?
when working with rest api we have different endpoints that describes every resources and might be complicated or too much routes ! in this case the graphQL comes with only a single endpoint named graphql/ .

yeah! a single endpoint for all your resources ! but how to get resources from different sources ? … GrapQL is a specification and it have a strongly type system that helps us to validate data types, also every resource it depends only on the code backed on. GraphQl isn’t a replacement for rest but we have to choose the best one for a specific case.

REST VS GRAPHQL

Let’s compare there two tools :

  • Over-fetching: when dealing with data fetching with rest this problem may occur, for example we want to get only the name of a student by querying his id like that : https://www.university.com/api/v1/student/<id> , the result will be all available information like name , id , class , age ... and much more !, this is a problem. we need just the name, this operation will produce some slowness in return response !
  • Under-fetching: this another problem with REST , for example we need to get all exam marks of a student, the routehttps://www.university.com/api/v1/student/<id> will not return the remaining data so we have to request another route like this https://www.university.com/api/v1/student/<id>/marks .
  • Multiple Round-Trips : with REST we have a lot of round-trips, each resource has it’s own route and when we make a lot of API calls will be very complex and confusing.

GraphQL : is designed to resolve these issues 😄, so no longer multiple round-trips, no longer under/over fetching . Just needed data is return back to user. it’s such a great thing ! really.

  • HTTP requests : REST is based on HTTP methods like GET POST PUT DELETE which correspond to getting a resource making a resource updating a resource deleting a resource . In graphQL there is three main schema types : Query mutation subscription to fetch and manipulate data.
  • Cashing system : this is an important concept for the response speed, REST is based on HTTP so by default it uses the HTTP cashing system.
    In GraphQL there is a different concept to handle this because they are all POST HTTP requests that no fully compatible with the standard HTTP cashing system, there is some libraries that can handle this like : apollo relay .
  • ERROR handling : in the world of HTTP there is a strong system for error handling, every error has it’s own code and description, so it’s easy to quickly figure out the problem. however, in GraphQL there is single query to fetch data from multiple resources , so errors may happens to the hole query or partially ! , and the returned error message may not be helpful 😢
    so you have to make an additional work to return a custom error message to clarify and mention the problem.

I don’t want to talk much 😃 let’s go to the demo … let’s go !!

Setting up the environment

To get started lets begin by setting up the environment, we will use the pipenv, you can install it with pip install pipenv.I assume that you have the latest python version installed in your system.

  1. Create a directory in your home folder : mkdir demo-grapql && cd demo-grapgl
  2. Make a virtual environment by running : pipenv shell, you should have now a file named Pipfile which contain all the packages that you will install.
  3. We need to install the graphene package by running this command pipenv install graphene .The package is the python graphql implementation.
  4. Create a file with the name schema.py by running this command touch schema.py and open the vscode editor in the current directory with this command code . .

Your First GraphQL Query

The schema.py file : run the script with python schema.py

import graphene
import json
class Query(graphene.ObjectType):
hello = graphene.String()
def resolve_hello(self, info):
return "world"
schema = graphene.Schema(query=Query)result = schema.execute(
'''
{
hello
}
'''
)
data = dict(result.data.items())
print(json.dumps(data,indent=2))

Expected result :

{
"hello": "world"
}

So what happens here !! we need graphene to work with graphql and json to format the return result.

Every GraphQL implementation needs a Query class that contains some fields , every field ( not always) must have a resolver function that return data related to the field. each filed is validated with a validation type system located on graphene.ObjectType .

Next, defining our schema by calling graphene.schema and passing our Query class to it . Then try to execute some queries.

Finally, parsing the result with result.data.items() that returns an ordered dict object, so we need to convert it to json as a final result.

Working with complex objects

We have tried a single field, lets try a complex one like a user definition.

...
import uuid
...class User(graphene.ObjectType):
id = graphene.ID(default_value=str(uuid.uuid4()))
username = graphene.String()
created_at = graphene.DateTime(default_value=datetime.now())
class Query(graphene.ObjectType):
users = graphene.List(User)
...
def resolve_users(self,info,limit=None):
return [
User(username="hatem"),
User(username="anouar"),
User(username="ines")
]
...
{
users{
id
username
createdAt
}
}
...

Expected result:

{
"users": [
{
"id": "4153f745-a155-454c-81f3-0ec9c91f8f86",
"username": "hatem",
"createdAt": "2019-11-29T15:07:35.550319"
},
{
"id": "4153f745-a155-454c-81f3-0ec9c91f8f86",
"username": "anouar",
"createdAt": "2019-11-29T15:07:35.550319"
},
{
"id": "4153f745-a155-454c-81f3-0ec9c91f8f86",
"username": "ines",
"createdAt": "2019-11-29T15:07:35.550319"
}
]
}

We define a User class with three fields id username created_at , then we need to add the user class to the Query class as a complex field, the return value of this field must be a list of users so we define it with graphene.List() and pass the User shape to it ( User class).

Now we have to set up the resolver with the name resolve_users and return some dummy data as a list (as we defined earlier).

Note1: we have two automatic values, the id is generated using uuid and the created_at is generated using the datetime.now() so we need to import respectively the uuid and datetime packages.

Note2: the created_at field must be called in the query by removing the ‘_’ and replace the ‘a’ with ‘A’ → createdAt else will throw an error.

Mutation with GraphQL

Now let’s try to add a User record, in this case we use the mutation specification from graphql:

...
class CreateUser(graphene.Mutation):
user = graphene.Field(User)
class Arguments:
username = graphene.String()
def mutate(self,info,username):
user = User(username=username)
return CreateUser(user=user)
...
class Mutation(graphene.ObjectType):
create_user = CreateUser.Field()
...
schema = graphene.Schema(query=Query) , mutation=Mutation)
...
"
mutation{
createUser(username:"hatem"){
user{
id
username
createdAt
}}}
"

Expected result:

{
"createUser": {
"user": {
"id": "2b392345-e469-4732-9f11-f2c25b0740f8",
"username": "hatem",
"createdAt": "2019-11-29T16:22:30.246645"
}
}
}

To create a User we need to create a class CreateUser and passing as always the graphene.ObjectType subclass . Then we define a single user as a filed type with a User class ( as a shape for the new user).

We must define also an inner class named arguments that contains the fields needed to create a user object ( manual input fields), and of course define it’s type.

The mutate function is required by the graphql system to apply the create operation, it has some parameters like self to access to class attributes, the info to get context variables that is may passed with the query, the username is what we need to get from user to create the User object.

Like we did with the Query class now we need a Mutation class and define a field create_user that takes the class name CreateUser .Notice that the query and mutation are root elements in the query structure.

Add the new class to the schema alongside with the query and execute the example mutation. it will return the recently created user.

You can find the full example here :

I add also in this file an example of create post so try to make it by your self 😃 as an exercise !

A useful presentation

Finally, I hope this tutorial is helpful to every one who need to get started with GraphQL. if you have any feedback please contact me hatem ben tayeb.
If you love the story make a claps 😃 !

Thank you 😄

--

--