13. Django REST API: API Documentation with Swagger/OpenAPI
Django REST API – API Documentation with Swagger/OpenAPI

In this post, we will generate documentation for our Django REST API using OpenAPI, Swagger UI, and Redoc.
API documentation makes it easier to understand, test, and share our endpoints with frontend developers, mobile developers, and other API consumers.



 

Why API documentation matters
When an API grows, it becomes difficult to remember every endpoint, request body, response format, authentication rule, and query parameter.

Good documentation helps developers understand how to use the API without reading the backend code directly.

Understanding available endpoints
Testing API requests
Knowing required fields
Checking response formats
Understanding authentication
Sharing the API with frontend or mobile developers

Without documentation, API users need to guess how the API works or constantly ask the backend developer for details.

 

What is OpenAPI?
OpenAPI is a standard format for describing REST APIs.

It describes the API endpoints, HTTP methods, request bodies, response formats, authentication methods, and other important details.

GET /api/projects/
POST /api/projects/
GET /api/tasks/
PATCH /api/tasks/1/
DELETE /api/tasks/1/

Request fields
Response fields
Status codes
Authentication rules
Query parameters

The OpenAPI schema is usually generated as a JSON or YAML document.

Tools like Swagger UI and Redoc can then use that schema to create interactive documentation pages.

 

Swagger UI vs Redoc
Swagger UI and Redoc are two popular ways to display OpenAPI documentation.

Swagger UI → Interactive API documentation and request testing
Redoc      → Clean and readable API reference documentation

Swagger UI is useful during development because it allows us to test requests directly in the browser.

Redoc is useful when we want a clean documentation page that is easy to read and navigate.

In this post, we will add both.

 

Installing drf-spectacular
To generate the OpenAPI schema, we will use drf-spectacular.

This package is designed to generate OpenAPI schemas from Django REST Framework projects and includes support for Swagger UI and Redoc.

pip install drf-spectacular

After installing it, we need to add it to our Django settings.

 

Adding drf_spectacular to settings.py
Open config/config/settings.py and add drf_spectacular to INSTALLED_APPS.

INSTALLED_APPS = [
    ...

    'rest_framework',
    'django_filters',
    'drf_spectacular',
    'projects',
]

This makes the package available inside the Django project.

 

Configuring the schema class
Now update the REST_FRAMEWORK configuration in config/config/settings.py.

We need to tell Django REST Framework to use the schema generator provided by drf-spectacular.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
        'rest_framework.filters.SearchFilter',
        'rest_framework.filters.OrderingFilter',
    ],
    'DEFAULT_PAGINATION_CLASS': 'projects.pagination.StandardResultsSetPagination',
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

The important line is:

'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',

This tells Django REST Framework how to generate the OpenAPI schema for our API.

 

Adding basic API metadata
We can also add some metadata for the generated documentation.

In config/config/settings.py, add the following configuration:

SPECTACULAR_SETTINGS = {
    'TITLE': 'Project Management API',
    'DESCRIPTION': 'A simple REST API built with Django REST Framework.',
    'VERSION': '1.0.0',
}

This information will appear in the generated documentation pages.

TITLE       → API name
DESCRIPTION → Short explanation of the API
VERSION     → API version

This is especially useful when the API is shared with other developers.

 

Adding schema and documentation URLs
Now we need to add URLs for the schema, Swagger UI, and Redoc.

Open config/config/urls.py and import the required views.

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

from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularSwaggerView,
    SpectacularRedocView,
)

Then add the documentation routes to urlpatterns.

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('projects.urls')),
    path('api-auth/', include('rest_framework.urls')),

    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

Now our project has three new documentation-related endpoints.

/api/schema/  → OpenAPI schema
/api/docs/    → Swagger UI
/api/redoc/   → Redoc documentation

 

Complete config/config/urls.py file
Your config/config/urls.py file should now look like this:

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

from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularSwaggerView,
    SpectacularRedocView,
)


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('projects.urls')),
    path('api-auth/', include('rest_framework.urls')),

    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

These routes expose the machine-readable schema and the human-friendly documentation pages.

 

Testing the documentation pages
Run the development server:

python manage.py runserver

Then open the documentation URLs in your browser:

OpenAPI Schema: http://localhost:8000/api/schema/
Swagger UI: http://localhost:8000/api/docs/
Redoc: http://localhost:8000/api/redoc/

The schema endpoint returns the OpenAPI document.

The Swagger UI and Redoc endpoints display that schema in a more readable way.

 

What Swagger UI shows
Swagger UI gives us an interactive interface for exploring and testing the API.

List endpoints
Inspect request bodies
Inspect response schemas
Check status codes
Send test requests
Test authentication

For example, you should see endpoints such as:

GET     /api/projects/
POST    /api/projects/
GET     /api/projects/{id}/
PUT     /api/projects/{id}/
PATCH   /api/projects/{id}/
DELETE  /api/projects/{id}/

GET     /api/tasks/
POST    /api/tasks/
GET     /api/tasks/{id}/
PUT     /api/tasks/{id}/
PATCH   /api/tasks/{id}/
DELETE  /api/tasks/{id}/

This is very helpful when testing the API during development.

 

What Redoc shows
Redoc provides a clean API reference page.

It is less focused on testing requests and more focused on readable documentation.

Clean API reference
Endpoint descriptions
Request and response schemas
Authentication information
Easy navigation sidebar

Redoc is useful when you want to share API documentation with other developers in a more polished format.

 

Documenting ViewSets automatically
Because our API uses ModelViewSet, serializers, filters, and pagination, drf-spectacular can automatically detect a lot of useful information.

Available endpoints
HTTP methods
Serializer fields
Request body structure
Response body structure
Path parameters
Pagination response structure
Filter parameters
Search parameter
Ordering parameter

This is one of the advantages of using standard Django REST Framework patterns.

The more consistent the API code is, the easier it is to generate documentation automatically.

 

Adding descriptions with extend_schema
Sometimes the automatically generated documentation is not descriptive enough.

We can improve it using extend_schema.

Open config/projects/views.py and import it:

from drf_spectacular.utils import extend_schema

Then we can add a description to a ViewSet.

@extend_schema(
    description='Manage projects owned by the authenticated user.'
)
class ProjectViewSet(viewsets.ModelViewSet):
    serializer_class = ProjectSerializer
    permission_classes = [IsAuthenticated]
    filterset_fields = ['created_at']
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'created_at']
    ordering = ['-created_at']

    def get_queryset(self):
        return Project.objects.filter(owner=self.request.user)

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

This description will appear in the generated documentation.

We can also document the task ViewSet:

@extend_schema(
    description='Manage tasks that belong to projects owned by the authenticated user.'
)
class TaskViewSet(viewsets.ModelViewSet):
    serializer_class = TaskSerializer
    permission_classes = [IsAuthenticated]
    filterset_fields = ['project', 'completed', 'created_at']
    search_fields = ['title', 'description']
    ordering_fields = ['title', 'completed', 'created_at']
    ordering = ['-created_at']

    def get_queryset(self):
        return Task.objects.filter(project__owner=self.request.user)

    def perform_create(self, serializer):
        project = serializer.validated_data['project']

        if project.owner != self.request.user:
            raise PermissionDenied('You cannot create tasks for this project.')

        serializer.save()

This helps API users understand the purpose and access rules of each resource.

 

Documenting serializers
The documentation also uses our serializers to understand request and response fields.

For example, our ProjectSerializer includes an owner field.

class ProjectSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')

    class Meta:
        model = Project
        fields = '__all__'

Because owner is read-only, the documentation can show that this field appears in responses but is not expected as input when creating a project.

owner appears in response
owner is not required in request body
owner is assigned automatically by the API

This is another reason why serializers are so important in Django REST Framework.

 

Authentication in documentation
Our API uses authentication, so some requests require a logged-in user.

In the browsable API, we used session authentication and the /api-auth/ login route.

/api-auth/login/
/api-auth/logout/

When testing through Swagger UI, authentication support depends on the authentication method configured in the API.

For simple learning projects, it is enough to know that protected endpoints are documented and still require authentication when used.

In a future project using JWT, Swagger UI can also be configured to send bearer tokens in the request headers.

Authorization: Bearer your_access_token_here

This is especially useful when documenting APIs consumed by React, mobile apps, or external services.

 

Generating the schema file
Besides serving the schema through a URL, we can also generate a schema file from the command line.

python manage.py spectacular --file schema.yml

This creates a file called schema.yml.

A schema file can be useful for sharing the API specification with other tools.

API documentation
Client generation
API testing tools
Contract testing
External integrations

The OpenAPI schema is not only for humans. It can also be used by other software tools.

 

Validating the schema
If you want to check the generated schema, you can use the validation option.

python manage.py spectacular --file schema.yml --validate

This helps detect possible schema issues early.

If the command shows warnings, read them carefully. Some warnings are harmless, but others may indicate that the documentation could be improved.

 

Improving documentation quality
Automatic documentation is useful, but it is not always perfect.

To improve documentation quality, keep your API code clear and explicit.

Use clear serializer field names
Use meaningful ViewSet names
Add descriptions with extend_schema when needed
Use proper validation messages
Keep filters and ordering fields explicit
Keep endpoints resource-based and predictable

Good API design produces better documentation automatically.

 

Protecting documentation in production
During development, public documentation is useful.

In production, you should decide whether the documentation should be public or restricted.

Public documentation
Private documentation for authenticated users
Documentation only available internally
Documentation disabled in production

For private APIs, it may be better to restrict access to documentation pages.

For public APIs, documentation is usually part of the developer experience.

The right choice depends on the type of API you are building.

 

Recommended setup
For this project, a practical documentation setup is:

Use drf-spectacular
Expose /api/schema/ for the OpenAPI schema
Expose /api/docs/ for Swagger UI
Expose /api/redoc/ for Redoc
Add API title, description, and version
Use extend_schema for important descriptions
Generate schema.yml when needed

This gives us useful documentation without manually writing every endpoint description from scratch.

 

What we have learned
In this post, we added API documentation to our Django REST API.

OpenAPI describes REST APIs in a standard format
Swagger UI provides interactive API documentation
Redoc provides clean API reference documentation
drf-spectacular generates OpenAPI schemas for DRF
DEFAULT_SCHEMA_CLASS connects DRF with drf-spectacular
/api/schema/ exposes the OpenAPI schema
/api/docs/ exposes Swagger UI
/api/redoc/ exposes Redoc
extend_schema can improve automatic documentation
Schema files can be generated from the command line

Our API is now easier to explore, test, and share with other developers.

 

What comes next?
In the next post, we will look at deployment notes for Django REST APIs.

We will review important production settings such as environment variables, allowed hosts, CORS, HTTPS, database configuration, and server setup.

Django REST API: Deployment Notes