
An API (Application Program Interface) is a regulated method of providing data to other applications and services. It’s a set of protocols for building and integrating application software. APIs lets your service or app communicate with other apps without having to know how they are built and implemented.
What is a RESTful API?
A RESTful API or simply REST (Representational State Transfer), is a type of API that uses HTTP requests to access data. Most REST APIs use JSON to send the payload. This is because JSON is lightweight and easy to interpret.
Some of the main types of requests in a REST API are:
- GET — retrieves resources from the API based on the endpoint and parameters passed
- POST — creates a new resource or record
- PUT — updates an existing resource or a record
- DELETE — deletes a resource or record at the given URI
Prerequisites
To follow along with this tutorial, it’s good to have at least some basic understanding of:
By the end of this tutorial, you will be able to:
- Install Django REST framework
- Serialize Django models
- Setup common HTTP requests
- Install and configure Cross-Origin Resource Sharing (CORS)
Let’s dive in!
Step 1 — Installing Django
It’s recommended to build Python projects in virtual environments. Let’s create a virtual environment for our project. Run the command below in a terminal.
$ python3 -m venv virtual
The command creates a new virtual environment virtual
in the current directory. Activate the environment by running:
$ source virtual/bin/activate
Then install the latest version of Django via PyPi using the command below.
$ pip install django
You can test Django installation in the python shell by running the command below:
$ python -m django --version
The command prints the version of your Django installation. If not installed, you will get a no module named django
error.
Step 3 — Creating a Django project
Now that there’s an activated virtual environment with Django installed let’s create a project. A Django project is a directory that contains all settings associated with a Django instance. This includes:
- Database configuration
- Language and time zone configurations
- Middleware configurations
- Debug configurations
- Template configurations
Run the command below to create a new Django project.
$ django-admin startproject rest
The command creates a new folder rest
in the current directory. Navigate to this folder in your terminal.
$ cd rest
The project directory tree should look like this:
.
├── rest
│ ├── manage.py
│ └── rest
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
To learn more about the generated files and folders, head over to the documentation.
Step 4 — Creating the API app.
Django comes with a utility that generates the basic folder structure of an app so that you can focus more on writing code rather than creating directories.
Run the command below to create a Django app.
$ python manage.py startapp api
The command generates a new api
folder with the following folder structure:
.
├── api
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
Step 5 — Registering the API app to the Project
Open the project directory in your code editor. Open settings.py
and add your api
app to the installed apps.
rest/settings.py
INSTALLED_APPS = [
#.....
'api',
]
Step 6 — Configuring URL routing
Since we’ll be creating only one app inside our Django project, we can point the base route of our project to our API app. Create a file urls.py
in the api
folder and put the following code.
api/urls.py
from . import views
from django.urls import path
urlpatterns = [
]
We import the views.py
file in the API directory and create an empty list of URL patterns. Let’s point the project URL to these URL patterns.
Edit the urls.py
file in the rest
folder to look like this:
rest/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('api.urls'))
]
Step 7 — Running the app
Time to run our app. Create the default database schema by running migrations using the following command.
$ python manage.py migrate
Then run the app in the local server using the following command.
$ python manage.py runserver
The app is served at localhost port 8000 by default. ie. http://127.0.0.1:8000. You can change the localhost port by appending the port number to the command above. For example to serve the app at port 7000, run the command below.
$ python manage.py runserver 7000

Step 8 — A simple API View
Let’s see what a simple API in Django looks like. Open views.py
and add the following code.
api/views.py
from django.http import JsonResponse
from rest_framework.decorators import api_view
@api_view(["GET"])
def index(request):
content = {"Message": "Hello World!"}
return JsonResponse(content)
We import the JsonResponse
class which allows us to return JSON in functions. We then create a GET
function index
that returns some JSON.
Let’s create a URL configuration for this function. Add the following code to urls.py
.
api/urls.py
#.....
urlpatterns = [
path('', views.index)
]
The function index is directed to the base app route. Reload your browser to see the API.

GET
API view Now that we have the simplest API running, let’s build a larger API. We’ll build a notes API. The API will be able to:
- Get existing notes
- Add notes to the Database
- Edit existing notes
- Delete notes
Step 9 — Installing Django REST framework
To build APIs more easily, we’ll be using Django REST framework. It helps us a lot, as we’ll not be hard-coding everything. Let’s install it using the command below.
$ pip install djangorestframework
Then, we’ll need to register the framework under installed apps in settings.py
. Edit the installed apps section in settings.py
to look like this:
rest/settings.py
#.....
INSTALLED_APPS = [
#.....
'api',
'rest_framework', # register rest framework
]
#.....
Step 10 — Creating a database model
Open models.py
and add the following code.
api/models.py
#......
class Note(models.Model):
title=models.CharField(max_length=200)
body=models.TextField()
date=models.DateField()
def __str__(self):
return self.title
The code creates a database Model Note
with the title, body and date properties.
Let’s create this database structure by running these 2 commands.
$ python manage.py makemigrations
$ python manage.py migrate
The makemigrations
command detects the changes in your models and makes migrations accordingly. Then the migrate
command applies the changes to the database.
Step 11 — Serializing the model
A serializer is a component that will convert Django models to JSON objects and vice-versa.
Create a file serializer.py
in your app directory and put the following code.
api/serializer.py
from rest_framework import serializers
from .models import Note
class NoteSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id','title','body','date')
We import serializers
module from the rest_framework
package. We then create NoteSerializer
class that inherits from the ModelSerializer
class. We then specify the model and fields we want to return. Now we need to create an API view to handle the requests.
Step 12 — Adding some Notes
Before we write the API view, let’s add some test notes. To do this, we need to:
- register
Note
model to admin dashboard - Create a superuser
- add notes
Open admin.py
and put the following code.
rest/admin.py
from django.contrib import admin
from . import models
admin.site.register(models.Note)
The code registers the Note model to the admin dashboard. Let’s create a superuser to login to the admin dashboard.
Run the following command and enter the credentials as prompted.
$ python manage.py createsuperuser
Now that you have an admin created, go to /admin
route .ie. http://127.0.0.1:8000/admin and log in using the credentials you created above. Add some notes by clicking Notes
and then Add Note

Step 13 — Getting notes list view
Add the following code inside views.py
.
api/views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Note
from .serializer import NoteSerializer
#.....
class NotesList(APIView):
def get(self, request, format=None):
all_notes = Note.objects.all()
serializers = NoteSerializer(all_notes,many=True)
return Response(serializers.data)
We import the Response
class from rest framework to handle API requests. We also import the APIView
as a base class for our API view function. We then create NoteList
class that inherits from the APIView
class. We then define a get
method that:
- queries the database to get all
Note
objects - serializes the model objects
- returns the serialized data as response
Let’s create a new URL configuration (URLConf) to handle requests to this model.
Step 14 — Creating API View URLConf
Edit the urlpatterns
under urls.py
to look like this:
api/urls.py
urlpatterns = [
#.....
path('notes', views.NotesList.as_view()),
]
And now your new view is ready. Go to the /notes
endpoint to view the results.

/notes
endpoint on a browser
/notes
endpoint in PostmanTesting the API
Testing an API is a critical thing in API building. To test this API, you can use any API testing tool or choose one from below.
- Postman. You can download Postman here.
- Postman chrome extension. Although this extension is deprecated, it’s still working and can be useful if you want to save your RAM. You can download the extension here.
- Rested Firefox extension. This is a Firefox extension that can be used to test APIs. You can download it here.
Step 15 — Adding notes to the database
It’s boring and illogical to be adding notes via the admin dashboard. Why don’t we write some code to enable us to add notes using the API?
Under views.py
add the following code.
api/views.py
from rest_framework import status
#.....
class Notes(APIView):
#.....
def post(self, request, format=None):
serializers = NoteSerializer(data=request.data)
if serializers.is_valid():
serializers.save()
return Response(serializers.data, status=status.HTTP_201_CREATED)
return Response(serializers.data, status=status.HTTP_400_BAD_REQUEST)
We import status
from rest framework to return status codes in each request. We also add a post
method that:
- serializes input data
- saves it to the database if the data is valid
- returns a 400 status code if the data is invalid
Making a post
request to the route /notes
and passing the note properties will add a new note to the database.

/notes
Step 16 — Getting a single note
Let’s say, you want to view a single note. You don’t have to scroll through a long list of notes. We can write some code to get that specific note.
api/views.py
class singleNote(APIView):
def get(self, request,pk, format=None):
try:
note = Note.objects.get(pk=pk)
serializers = NoteSerializer(note)
return Response(serializers.data)
except Note.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
We create another API View class singleNote
. Inside it, we create a get
method that:
- gets a note from the database by id
- serializes it if the note exists
- returns the data
- returns a 404 status code if the note does not exist
Let’s create a URLConf for the singleNote
class. Open urls.py
and add the code.
api/urls.py
urlpatterns = [
#.....
path('notes/<pk>', views.singleNote.as_view())
]
At this point, if you make a get
request at /notes/1
.ie http://127.0.0.1:8000/notes/1 you’ll get the details of the note id
1.

/notes/<id>
Step 17 — Editing existing notes
Let’s say we add a note and there’s a typo in between. Do you always have to go to the admin dashboard? NO. We can set up another method to do that for us.
To edit existing notes, we’ll need to identify the note by an id. Let’s add another method inside the singleNote
class.
api/views.py
class singleNote(APIView):
#.....
def put(self, request, pk, format=None):
note = Note.objects.get(pk=pk)
serializers = NoteSerializer(note, request.data)
if serializers.is_valid():
serializers.save()
return Response(serializers.data)
else:
return Response(serializers.errors,status=status.HTTP_400_BAD_REQUEST)
The put
method above:
- gets a note id
- serializes input data
- saves the serialized data to the identified note if the data is valid.
- returns a 400 status code if the input data is invalid
If you make a put
request at /notes/1
, the note id 1 will be updated.

PUT
request at /notes/<id>
Step 17 — Deleting a note
To delete a single note, delete()
method. A note is identified by id and then deleted. Let’s add another function inside the singleNote
class.
api/views.py
class singleNote(APIView):
#.....
def delete(self,request, pk, format=None):
try:
note = Note.objects.get(pk=pk)
note.delete()
return Response(status=status.HTTP_200_OK)
except:
return Response(status=status.HTTP_404_NOT_FOUND)
The delete
method above:
- gets a note by id
- deletes the note
- returns a 200 status code on deletion
- returns a 404 status code if the note does not exist
Making a delete
request at /notes/1
will delete note id 1.

DELETE
request at /notes/<id>
Cross-Origin Resource Sharing (CORS)
If your API is to be accessed by some front-end or a remote machine, you’ll need to set up CORS. Django-cors-headers is a package that sets up CORS in Django. Install it via PyPI using the command below.
$ pip install django-cors-headers
Then register the package under installed apps in settings.py
.
rest/settings.py
INSTALLED_APPS = [
#.....
'rest_framework',
'corsheaders'
]
You’ll also be required to add CORS middleware to listen in on responses.
rest/settings.py
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
#.....
]
Finally, configure allowed origins. You can either:
- set a list of allowed origins under
CORS_ALLOWED ORIGINS
- allow all origins by setting
CORS_ALLOW_ALL_ORIGINS
toTrue
# allowing selected origins
CORS_ALLOWED_ORIGINS = [
"https://example.com",
#etc...
]
# allowing all origins
CORS_ALLOW_ALL_ORIGINS = True
Returning clean JSON.
By default, Django REST framework returns an inbuilt page along with your JSON at every route. You can remove it by returning pure JSON from your view functions. To do this, you’ll need to import JsonResponse
from the Django http
package.
api/views.py
from django.http import JsonResponse
You’ll then return output using JsonResponse
instead of Response
from your methods. You’ll also be required to set the safe
parameter to False
since Django doesn’t allow serializing non-dictionary objects by default.
api/views.py
return JsonResponse(serializers.data, safe=False)

JsonResponse
The code in this tutorial can be found in GitHub.
Summary
We’ve looked at how you can set up a RESTful API in Django. REST APIs can be made with the help of the Django REST framework. It makes it easier to set up the API as you don’t have to hard-code everything. We have created a simple notes API and looked at how we set up the common types of HTTP requests in Django. If CORS headers are not set up, integration with front-end services is impossible.
Happy Coding!!!