A Brief Introduction to GraphQL

Introduction

GraphQL is a query language for API(Application Programming Interface) and is an alternative to building APIs. It allows for the definition of the structure of the data required and prevents the return of an excessive amount of data from the server.

Many API developers use GraphQL to build APIs because GraphQL APIs are fast, flexible, and user-friendly. And also GraphQL APIs allows user to request what exactly they need. GraphQL is developed by Facebook in 2012 and publicly released in 2015.

 

GraphQL Vs REST

1. Multiple endpoints

REST APIs have multiple endpoints whereas GraphQL APIs have only one endpoint. In the case of REST APIs, API fetches data on basis of endpoints whereas, in the case of GraphQL, API fetches data on the basis of queries that users make on the client-side.

 

2. REST APIs have a problem with multiple round trips

This means that API will hit multiple endpoints to get the required data. For example: Suppose the user wants to get the title of all the blogs. For this the endpoints that API will hit be ‘https:pythonsansar.com/blog/title’. One can see that API hit two endpoints to get the title of the blogs(/blog/title).
But in the case of GraphQL, same to fetch the same data, the user schema looks like this

query{
    blog{
        title
    }
}

 

3. Over fetching problem

Suppose a user wants to fetch the name of the authors. For this, API will hit the endpoint ‘https://pythonsansar.com/author’. This will return other information such as the email of the author, date joined, id, etc. along with the name. Since the API returns unnecessary data other than the name of the author, it is known as an over-fetching problem.

 

4. Under fetching problem

As we can see that when API hits the endpoint ‘https://pythonsansar.com/author’, the returned data is not the required one(which is only the name of the author). This is called the under fetching problem in REST APIs.

 

5. REST APIs are slower than GraphQL APIs.

In this blog, we are going to make a simple Books API using a graphene library provided by python. I assume that you have already installed python on your machine and graphene is supported by django>=1.11. I am using conda for creating a virtual environment and if you don’t have conda on your machine I suggest you install conda(Installation of Conda) or user pipenv or virtualenv for creating a virtual environment.

 

Implementation

Step1: Setting up a virtual environment and installing required libraries

Open your command prompt

C:\> mkdir Book
C:\> cd Book
C:\Book\> conda create -n graphql_tutorial python=3.10

 

Activate environment

C:\Book\> conda activate graphql_tutorial

 

After activating your virtual environment, you will see the name of the environment left-hand side of your current path, then run the following commands:

(graphql_tutorial)C:\Book\> pip install django 
(graphql_tutorial)C:\Book\> pip install grahene-django 
(graphql_tutorial)C:\Book\> pip install django-graphql-jwt
(graphql_tutorial)C:\Book\> code .

I am using VS Code for this demonstration. So, command code. will open the current directory in VS code. If you are using any other IDEs then make sure to open the created folder in your favorite IDE.

 

Step 2: Creating a Django project and adding graphene to your Django project

(graphql_tutorial)C:\Book\> django-admin startproject Books

 

Make sure that your virtual environment is activated and that you are on the right path. Then run your Django project using the following command:

(graphql_tutorial)C:\Book\> cd Books
(graphql_tutorial)C:\Book\Books\> python manage.py runserver

If you see the Django welcome page, then you are doing great till now. If you didn’t see the Django Welcome page, kindly revisit the steps and try again.

admin-page-django

Step 3: Creating an app with the name API

(graphql_tutorial)C:\Book\Books\> python manage.py startapp Api

After creating an app, open your settings.py file and add your app and graphene inside INSTALLED_APPS
settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Api',
    'graphene_django',
    'django_filters',
]

GRAPHENE = {
    "SCHEMA" : 'Books.schema.schema',
    "MIDDLEWARE": [
        "graphql_jwt.middleware.JSONWebTokenMiddleware",
    ],
}

 

Creating Book model
Api > models.py

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=50)
    author = models.CharField(max_length=50)
    description = models.TextField()

    def __str__(self):
        return self.title

We created a Book model having fields like title, author, and description. Now migrate the changes in the database with the following command:

(graphql_tutorial)C:\Book\Books\> python manage.py makemigrations
(graphql_tutorial)C:\Book\Books\> python manage.py migrate

 

After migrating the changes, register the previously created model in your app’s admin.py file
Api > admin.py

 from django.contrib import admin
 from .models import Book

 # Register your models here.
 admin.site.register(Book)

 

Also, add the urls.py file inside the Api folder

Api > urls.py

from django.contrib import admin
from django.urls import path

urlpatterns = [
    
]

 

Now, create a superuser account by running the following command

(graphql_tutorial)C:\Book\Books\> python manage.py createsuperuser

 

After creating a superuser account, open the link http://127.0.0.1:8000/admin/ to your browser and log in with previously created user credentials. Then you will see something like this

 

Then add some data in your database manually(later we will learn to add data in the database with graphql). This looks something like this

graphql-output

 

Now, we are going to write a schema for our API. Create a new file with the name schema.py in your app
Api > schema.py

import graphene
from .models import Book
from graphene_django import DjangoObjectType


class BookType(DjangoObjectType):
    class Meta:
        model = Book
        fields= "__all__"

class BookQuery(graphene.ObjectType):
    book_element = graphene.List(BookType)

    def resolve_book_element(root, info, **kwargs):
        return Book.objects.all()

 

Now, add the schema.py file in the Books folder(Django project) and the following code

Books > schema.py

import graphene
import Api.schema

class Query(Api.schema.BookQuery):
    pass

schema = graphene.Schema(query=Query)

 

Now, open the urls.py file of your Django project and add the following:

Books > urls.py

from graphene_django.views import GraphQLView
from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('Api.urls')),
    path('graphql/', GraphQLView.as_view(graphiql=True)),
]

 

Now, open the link http://127.0.0.1:8000/graphql/ in your browser and make a query as shown below:

graphql-output

Conclusion

In this tutorial, we came to know the difference between REST API and Graphql API. Gaphql provides more flexibility and is user-friendly. There is no problem with over and under fetching in Graphql. Also, there is no problem with multiple round trips.

Check out:

6 thoughts on “A Brief Introduction to GraphQL”

  1. Thanks a lot for your reply. I have followed the codes exactly as in the tutorial and it seems working fine till editing the url.py in Books directory. At this point, I got:
    ——————————————————–
    [13/Nov/2021 05:38:33] “GET /static/admin/js/actions.js HTTP/1.1” 304 0
    C:\Users\Future\Desktop\Book\Books\Books\urls.py changed, reloading.
    Watching for file changes with StatReloader
    Performing system checks…

    Exception in thread django-main-thread:
    Traceback (most recent call last):
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\threading.py”, line 1009, in _bootstrap_inner
    self.run()
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\threading.py”, line 946, in run
    self._target(*self._args, **self._kwargs)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\utils\autoreload.py”, line 64, in wrapper
    fn(*args, **kwargs)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\core\management\commands\runserver.py”, line 118, in inner_run
    self.check(display_num_errors=True)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\core\management\base.py”, line 419, in check
    all_issues = checks.run_checks(
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\core\checks\registry.py”, line 76, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\core\checks\urls.py”, line 13, in check_url_config
    return check_resolver(resolver)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\core\checks\urls.py”, line 23, in check_resolver
    return check_method()
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\urls\resolvers.py”, line 412, in check
    for pattern in self.url_patterns:
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\utils\functional.py”, line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\urls\resolvers.py”, line 598, in url_patterns
    patterns = getattr(self.urlconf_module, “urlpatterns”, self.urlconf_module)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\utils\functional.py”, line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\urls\resolvers.py”, line 591, in urlconf_module
    return import_module(self.urlconf_name)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\importlib\__init__.py”, line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
    File “”, line 1050, in _gcd_import
    File “”, line 1027, in _find_and_load
    File “”, line 1006, in _find_and_load_unlocked
    File “”, line 688, in _load_unlocked
    File “”, line 883, in exec_module
    File “”, line 241, in _call_with_frames_removed
    File “C:\Users\Future\Desktop\Book\Books\Books\urls.py”, line 8, in
    path(”, include(‘Api.urls’)),
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\site-packages\django\urls\conf.py”, line 34, in include
    urlconf_module = import_module(urlconf_module)
    File “C:\Users\Future\anaconda3\envs\graphql_tutorial\lib\importlib\__init__.py”, line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
    File “”, line 1050, in _gcd_import
    File “”, line 1027, in _find_and_load
    File “”, line 1004, in _find_and_load_unlocked
    ModuleNotFoundError: No module named ‘Api.urls’

    Reply
    • There has been a mistake in settings.py file.

      We’ve updated the settings.py file please have a look.

      Also inside Api add urls.py file
      Api>urls.py
      urlpatterns = []

      And we do apologize for this mistake.
      If there’s an still error feel free to ask

      Reply
  2. Thank you very much again. Again I followed the steps from the start point and when navigating to http://127.0.0.1:8000/admin/, I found Groups and Users but didn’t find “Books” at all. That’s weird. It appeared with me in the previous test before you edit the tutorial.

    Reply
    • we’ve again updated the blog. Please have a look. We’ve updated settings.py file added schema.py file in Books folder. Please revisit the blog. Thank you

      Reply
  3. Thank you very much. Now everything is OK. I have to install more packages during the process. Just to add to your tutorial
    pip install django-filter
    pip install django-graphql-jwt
    And please fix the typo in:
    pip install graphene-django

    Reply

Leave a Comment