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.
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
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:
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:
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’
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
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.
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
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
Ok.