How to use Swagger-ui with Django REST API in 8 minutes

Oyedotun Teslim
8 min readMar 3, 2023

--

At the end of this tutorial you will be able to create your first API using DRF and swagger UI.

The essence of this tutorial is to document a step by step approach that any beginner can reference to implement their Djangorestframework and swagger-ui, of course I don’t want them to face the difficulty I faced when I was learning it. In this tutorial, you will implement a simple user authentication API using DRF and JWT. The entire API will be document using Swagger UI.

Prerequisite

  • Install Python
  • Python virtual environment (recommended)
  • Text editor of choice ( here, I used VS code)
  • Understanding of Django API
  • Basic Django

So let begin

Steps:

1. Create and Activate Python Virtual Environment. To do these, run the following commands

1.1 To create virtual environment for your project on windows:

Virtualenv name-env

1.2 To activate virtual environment :

There several ways but I’m going for this approach

source name-env/scripts/activate

After creating virtual environment for Myproject

1.3 Why using virtual environments?

Virtual environments allow you to install packages and dependencies without interfering with your system-wide Python installation. This makes it easier to manage dependencies and avoid conflicts between packages.

After activating nsme-env environment

1.4 After activating your virtual environment install the following:

pip install Django
pip install djangorestframework
pip install drf-yasg

pip install djangorestframework-simplejwt
pip install PyJWT

2 Creating a Django project

2.1 Setup

2.1.1 Creating a new Project

To create a new Django project, use the following command:

django-admin startproject Myproject

2.1.2 Myproject structure look like this:

Project1/
manage.py
project1/
__init__.py
settings.py
urls.py

2.2 Running the development server

To run the development server, navigate to Myproject directory and run the following command:

python manage.py runserver

You should see something like this:
Watching for file changes with StatReloader
Performing system checks…

System check identified no issues (0 silenced).
March 03, 2023–22:36:53
Django version 4.1.7, using settings ‘Myproject.settings’
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

paste http://127.0.0.1:8000/ to your web browser and you will see this

Django homepage

2.3 Create a Django App:

A Django project can contain one or more apps. An app is a self-contained module that encapsulates a specific functionality. To create a new app, run the following command in the terminal or command prompt:

·python manage.py startapp Myapp

Replace “Myapp” with the name you want to give to your app.

2.3.1 Django Myapp structure look like this:

  • Myapp/
    __init__.py
    admin.py
    models.py
    tests.py
    views.py

2.3.2 The Entire Django project structure now look like this:

MyProject/
manage.py

Myapp/
__init__.py
admin.py
models.py
tests.py
views.py
myproject/
__init__.py
settings.py
urls.py

2.4 Now that we have successfully created application “myapp”, in Django project “Myproject” we created early, To do this, we need to update the INSTALLED_APPS in the file settings.py for our project. This is shown below:

# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#register myapp
"Myapp",
#tell django you are creating api
"rest_framework",
#add other dependencies
'drf_yasg',
'rest_framework_simplejwt',
'rest_framework_simplejwt.token_blacklist',
'rest_framework.authtoken',
]

2.5 Now in the models.py file paste the following lines of code

from django.contrib.auth.models import AbstractUser
from django.db import models
from rest_framework_simplejwt.tokens import RefreshToken
from django.conf import settings

class User(AbstractUser):
email = models.EmailField(unique=True, max_length=50)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'username'] # add phone number as a requirement while signing up
def __str__(self) -> str:
return f'{self.first_name} {self.last_name}'
def __str__(self):
return "{}".format(self.email) def tokens(self):
refresh= RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token)
}

2.6 Next is to register this model inside our admin.py file in Myapp, open the admin.py file, and put the following code:

from django.contrib import admin

#register your models her
from .models import User
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ['id', 'email', 'first_name','first_name', 'password', 'username'
]

2.7 Add this to your settings.py file

AUTH_USER_MODEL = ‘Myapp.User’

Run the following two commands to make migrations of the changes made so far.

python manage.py makemigrations
python manage.py migrate

2.9 Creating superuser

run this command and supply your details

python manage.py createsuperuser

To have access to admin page where you can login with your credential visit URL http://127.0.0.1:8000/admin/

Before Login
After Login

3. Now let’s create the serializers for Myapp, but before that, let me briefly explain serializers. Serializers are responsible for converting complex data types, such as Django models, into JSON, which can be easily consumed by other applications.

3.1 Create a serializers.py file inside the Myapp folder and write the following code inside it.

from rest_framework import  serializers
from .models import User
from django.contrib import auth
from rest_framework.exceptions import AuthenticationFailed

class UserSerializers(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'password']
extra_kwargs = {'password': {'write_only': True}}

def create(self, validated_data):
user = User(
email=validated_data['email'],
username=validated_data['username'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name']
)
user.set_password(validated_data['password'])
user.save()
return user



# login serializer start here
class LoginSerializer(serializers.ModelSerializer):
email=serializers.EmailField(max_length=255,min_length=3)
password=serializers.CharField(max_length=68, min_length=6,write_only=True)
username=serializers.CharField(max_length=255,min_length=3, read_only=True)
tokens=serializers.SerializerMethodField()
def get_tokens(self,obj):
user = User.objects.get(email=obj['email'])
return {
'access':user.tokens()['access'],
'refresh':user.tokens()['refresh']
}
class Meta:
model=User
fields=['email','password','username','tokens']
def validate(self, attrs):
email = attrs.get('email', '')
password=attrs.get('password', '')
user = auth.authenticate(email=email, password=password)
if not user:
raise AuthenticationFailed('Invalid credentials, try again')
attrs['user'] = user
return attrs

3.2 Now let’s create views for our serializers, in views.py file inside the Myapp. Generic APIVIEW was used to create user, you can read more here write the following code:

from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import generics,status
from .serializers import LoginSerializer,UserSerializers
from .models import User
from .permission import IsLoggedInUserOrAdmin, IsAdminUser
from rest_framework.permissions import IsAuthenticated

#for viewing all user with admin permission
class UserListAPIView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializers
permission_classes = [IsAuthenticated,IsAdminUser]
# to signup by anyone
class UserCreateAPIView(generics.CreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializers
permission_classes = [permissions.AllowAny]
#view user detail by authenticated user or admin
class UserRetrieveAPIView(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializers
permission_classes = [IsLoggedInUserOrAdmin]
# update user profile by authenticate user
class UserUpdateAPIView(generics.UpdateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializers
permission_classes = [IsAuthenticated,IsLoggedInUserOrAdmin]


#delete user by only admin
class UserDestroyAPIView(generics.DestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializers
permission_classes = [IsAuthenticated,IsAdminUser]
#login users
class LoginAPIView(generics.GenericAPIView):
serializer_class=LoginSerializer
permission_classes=[permissions.AllowAny]
def post(self, request):
serializer=self.serializer_class(data=request.data)
serializer.is_valid(raise_exception= True)

return Response(serializer.data, status=status.HTTP_200_OK)


3.3 We want to define some permissions for our API, so create permission.py file inside Myapp and paste the following code:

from rest_framework import permissions
class IsLoggedInUserOrAdmin(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj == request.user or request.user.is_staff
class IsAdminUser(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_staff
def has_object_permission(self, request, view, obj):
return request.user and request.user.is_staff

3.4 Create urls.py inside Myapp, after that paste this code:

from django.urls import path
from.views import *

urlpatterns = [
path('user-lists/', UserListAPIView.as_view(), name='user-list'),
path('users/', UserCreateAPIView.as_view(), name='user-create'),
path('users/<int:pk>/', UserRetrieveAPIView.as_view(), name='user-retrieve'),
path('users/<int:pk>/update/', UserUpdateAPIView.as_view(), name='user-update'),
path('users/<int:pk>/delete/', UserDestroyAPIView.as_view(), name='user-delete'),
path ('login/',LoginAPIView.as_view(), name = 'login'),
]

3.5 Adding Swagger UI:

Now we want to add swagger ui to our api, but before that

What is swagger ui?

Swagger UI is a user-friendly interface for testing and documenting APIs. It allows developers to interact with APIs by sending requests and viewing responses, and it generates documentation for APIs automatically based on the API specification.

3.6 Add the following to urls inside Myproject/Myproject:


from django.contrib import admin
from django.urls import path,include
#swagger config
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
#jwt view
from rest_framework_simplejwt.views import (TokenObtainPairView, TokenRefreshView,)

#swagger views settings

schema_view = get_schema_view(
openapi.Info(
title="Swagger with django API",
default_version='v1',
description="powered by spaceyatech and Tamarcom Technology",
terms_of_service="https://www.ourapp.com/policies/terms/",
contact=openapi.Contact(email="contact@expense.local"),
license=openapi.License(name="Test License"),),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
path('admin/', admin.site.urls),
#add Myapp urls here
path('', include("Myapp.urls")),
# for swagger ui
path ('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path ('api/api.json', schema_view.without_ui( cache_timeout=0), name='schema-swagger-ui'),
path ('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]


3.7 Add a dictionary with the name SWAGGER_SETTINGS in the settings.py file which will allow us to pass the JWT token inside the Swagger UI for authentication

from datetime import  timedelta
#setting for simplejwt
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': True,
}
#swagger settings
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'Bearer':{
'type':'apiKey',
'name':'Authorization',
'in':'header'
}
}
}

3.8 Also add REST_FRAMEWORK_SETTINGS inside the settings.py

REST_FRAMEWORK = {

'DEFAULT_AUTHENTICATION_CLASSES': (

'rest_framework_simplejwt.authentication.JWTAuthentication',

),
'DEFAULT_PERMISSION_CLASSES':[
'rest_framework.permissions.IsAuthenticated',
],

'NON_FIELD_ERRORS_KEY': 'error',

}

4.0 Now refresh your browser, you should see this

Swagger UI Interface

4.1 Authentication Endpoints

User Endpoints

4.1.1 Register User:

This endpoint allow new user to signup. No authentication or authorization is required to access this endpoint.

signup request
Signup Response

4.2 Protected endpoint :

Unauthenticated and unauthorized user will not be able to access this endpoint. Only authenticated and authorized user can view user details, meaning you must have logging and have required permission (i.e you can only view you details, and not other user’s details) before you can access this endpoint. In this example, I didn’t sign in before sending request, so i got error message “authenticated credential is required.

Unauthenticated User Request
Response

4.3 Authenticating User

Request
Response

4.4 Authorizing User: Immediately after login, you will receive access token for authorization. past the access token in the authorization dialog box precede by Bearer:

BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjc4OTc3MzU2LCJpYXQiOjE2Nzg5NzQzNTYsImp0aSI6ImQyMjQ0YTlkYjgyYjQ1NzQ4MTkyNDgwYzgwOTBkOGUzIiwidXNlcl9pZCI6NX0.afIdlrFCPRfHZn7NzU0ZX_GpysT4C580D3BI-em-7MM

Note : the access token is set to expired in 30 minute time, you can set yours to meet your requirements.

Authorizing User

4.4.1 After authorizing user close the dialog box and continue your testing, you now have access to the protected endpoints you are authorized to access.

User Authorized

4.5 Viewing user details after authentication and authorization: view your details by passing your id, in my case 5.

Request
Response

5.0 Summarily

We have successfully created user API using Django restframework, simple_Jwt and Swagger UI. In this API we have 7 different endpoints — — create_user endpoint to signup new user, no authentication or authorizations is required to signup. Signing endpoint authenticate users. User_lists endpoint list all the users in the database. Only admin user is allow to view or delete all users . While individual user are allow to view their details or update their profile after authentication and authorization.

Thanks for reading….

watch-out for part2 where user can add products….

--

--

No responses yet