Forem

Cover image for How to Use Swagger UI with Django
kihuni
kihuni

Posted on

How to Use Swagger UI with Django

Introduction

Clear and interactive documentation is essential in API development. It ensures that developers can easily understand and utilize your API, reducing confusion and speeding up the integration process. One of the best tools for achieving this is Swagger UI, which provides an interactive interface for your API documentation based on the OpenAPI Specification (OAS). In this guide, we will explore how to integrate Swagger UI with a Django Blog API project, making your API documentation user-friendly and accessible.

Why Use Swagger UI?

Swagger UI is a powerful tool that automatically generates interactive API documentation from an OpenAPI specification. It allows developers to:

  • Explore API endpoints through a visual interface.
  • Test API requests directly from the browser.
  • Understand request and response structures without needing to sift through the code.

While other documentation tools like ReDoc offer various features, Swagger UI stands out for its interactive design and ease of implementation. This makes it a valuable tool for helping developers understand and test your API directly from the documentation.

Project Setup: Our Blog API

We will create a simple Blog API using Django REST Framework to demonstrate the integration of Swagger UI. Our API will allow users to:

  • Create, read, update, and delete blog posts.
  • Add and manage comments on blog posts.
  • Tag and categorize blog posts.

Prerequisites

Before we begin, ensure you have the following:

  • Python 3.8 or higher installed.
  • Basic familiarity with Django and Django REST Framework.
  • A code editor (e.g., VS Code, PyCharm).

Step 1. Create a New Django Project

Let’s start by setting up a new Django project.

# Create a virtual environment
python -m venv blogapi_env
source blogapi_env/bin/activate  # On Windows: blogapi_env\Scripts\activate

# Install Django and DRF
pip install django djangorestframework

# Start a new Django project
django-admin startproject blogapi
cd blogapi

# Create the blog app
python manage.py startapp blog
Enter fullscreen mode Exit fullscreen mode

Step 2. Define Models

Next, let’s define the models for our blog in blog/models.py.

from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    categories = models.ManyToManyField(Category, related_name='posts')

    def __str__(self):
        return self.title

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Comment by {self.author.username} on {self.post.title}"
Enter fullscreen mode Exit fullscreen mode

Step 3. Create Serializers

Now, let’s create serializers in blog/serializers.py to convert our models into JSON format.

from rest_framework import serializers
from .models import Category, Post, Comment
from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email')

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id', 'name')

class CommentSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('id', 'post', 'author', 'content', 'created_at')
        read_only_fields = ('post',)

class PostSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    comments = CommentSerializer(many=True, read_only=True)
    categories = CategorySerializer(many=True, read_only=True)

    class Meta:
        model = Post
        fields = ('id', 'title', 'content', 'author', 'created_at', 'updated_at', 'categories', 'comments')
Enter fullscreen mode Exit fullscreen mode

Step 4. Create Views

Let’s create our views using DRF’s ViewSets in blog/views.py.

from rest_framework import viewsets
from .models import Category, Post, Comment
from .serializers import CategorySerializer, PostSerializer, CommentSerializer
from rest_framework.permissions import IsAuthenticatedOrReadOnly

class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        post_id = self.kwargs.get('post_pk')
        post = Post.objects.get(pk=post_id)
        serializer.save(author=self.request.user, post=post)
Enter fullscreen mode Exit fullscreen mode

Step 5. Configure URLs

Create URL patterns in blog/urls.py.

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CategoryViewSet, PostViewSet, CommentViewSet

router = DefaultRouter()
router.register(r'categories', CategoryViewSet)
router.register(r'posts', PostViewSet)
router.register(r'comments', CommentViewSet)

urlpatterns = [
    path('', include(router.urls)),
]
Enter fullscreen mode Exit fullscreen mode

Update the main blogapi/urls.py.

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('blog.urls')),
]
Enter fullscreen mode Exit fullscreen mode

Step 6. Run Migrations and Start the Server

Run the following commands to apply migrations and start the development server.

# Create and apply migrations
python manage.py makemigrations
python manage.py migrate

# Start the server
python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Visit http://127.0.0.1:8000/api/ to see your API endpoints.

swagger ui

Integrating Swagger UI with Our Blog API

With our basic Blog API established, it’s time to integrate Swagger UI to offer interactive documentation.

Step 1: Install Required Packages

Install the necessary packages for integrating Swagger UI.

pip install drf-spectacular drf-spectacular-sidecar
Enter fullscreen mode Exit fullscreen mode
  • drf-spectacular: Generates OpenAPI schemas for your DRF API.
  • drf-spectacular-sidecar: Serves static files for Swagger UI, making it easier to use with CSP or other security measures.

Step 2. Configure Django Settings

Update your blogapi/settings.py file to include drf-spectacular.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'blog',
    'drf_spectacular',  # Add this line
]

# Configure REST Framework settings
REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ],
}

# Configure Spectacular settings
SPECTACULAR_SETTINGS = {
    'TITLE': 'Blog API',
    'DESCRIPTION': 'API for managing blog posts, comments, and categories',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
}
Enter fullscreen mode Exit fullscreen mode

Step 3. Add Swagger UI Endpoints

Update your blogapi/urls.py to include the Swagger UI endpoints:

from django.contrib import admin
from django.urls import path, include
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('blog.urls')),

    # Swagger UI endpoints
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
]
Enter fullscreen mode Exit fullscreen mode

Visit http://127.0.0.1:8000/api/docs/ to see the Swagger UI interface.

API Document

Step 4: Enhance API Documentation Using Decorators

To make our API documentation more informative, we will use decorators to add descriptions and response examples. Update blog/views.py.

from rest_framework import viewsets
from .models import Category, Post, Comment
from .serializers import CategorySerializer, PostSerializer, CommentSerializer
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from drf_spectacular.utils import extend_schema, extend_schema_view

@extend_schema_view(
    list=extend_schema(description='Get a list of all categories'),
    retrieve=extend_schema(description='Get details of a specific category'),
    create=extend_schema(description='Create a new category'),
    update=extend_schema(description='Update an existing category'),
    destroy=extend_schema(description='Delete a category')
)
class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer

@extend_schema_view(
    list=extend_schema(
        description='Get a list of all blog posts',
        responses={200: PostSerializer(many=True)}
    ),
    retrieve=extend_schema(
        description='Get details of a specific blog post including comments',
        responses={200: PostSerializer}
    ),
    create=extend_schema(
        description='Create a new blog post',
        responses={201: PostSerializer}
    ),
    update=extend_schema(
        description='Update an existing blog post',
        responses={200: PostSerializer}
    ),
    destroy=extend_schema(
        description='Delete a blog post',
        responses={204: None}
    )
)
class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

@extend_schema_view(
    list=extend_schema(description='Get a list of all comments'),
    retrieve=extend_schema(description='Get details of a specific comment'),
    create=extend_schema(description='Create a new comment on a post'),
    update=extend_schema(description='Update an existing comment'),
    destroy=extend_schema(description='Delete a comment')
)
class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        post_id = self.kwargs.get('post_pk')
        post = Post.objects.get(pk=post_id)
        serializer.save(author=self.request.user, post=post)
Enter fullscreen mode Exit fullscreen mode

Testing Your Blog API with Swagger UI

Now that we have Swagger UI set up, let's try out some API operations.

Step 1. Create a superuser

Create a superuser to authenticate in Swagger UI.

python manage.py createsuperuser
Enter fullscreen mode Exit fullscreen mode

Swagger UI

Step 2 Test Endpoints

Use Swagger UI to test endpoints like creating categories, posts, and comments. For example:

Creating a New Category

1. In Swagger UI, expand the POST /api/categories/ endpoint
2. Click the "Try it out" button
3. Enter a sample category name in the request body:

{
  "name": "Technology"
}
Enter fullscreen mode Exit fullscreen mode

4. Click "Execute"
5. You should see a successful response with status code 201 Created

Post

Creating a Blog Post

1. In Swagger UI, expand the POST /api/posts/ endpoint
2. Click the "Try it out" button
3. Enter a sample post in the request body:

{
  "title": "Introduction to Swagger UI",
  "content": "This is a post about integrating Swagger UI with Django REST Framework...",
  "categories": [1]
}
Enter fullscreen mode Exit fullscreen mode

4. Click "Execute"
5. You should see a successful response with status code 201 Created

post blog

Conclusion

Integrating Swagger UI with Django REST Framework for our Blog API project has significantly improved our API documentation. By following the steps in this guide, you’ve created an interactive, user-friendly interface that allows developers to explore and test your API endpoints directly from their browsers.

If you’d like to explore the full implementation, check out the complete code on GitHub. Feel free to clone the repository, experiment with the code, and use it as a starting point for your own projects.

Remember that good documentation is an ongoing process. As you add new features to your Blog API, make sure to update your schema descriptions and examples to keep your documentation comprehensive and current.

Resource

Top comments (0)