Introduction
Good documentation is as important as good code. OpenAPI (formerly Swagger) is the industry standard for describing REST APIs. It enables automatic documentation generation, client SDK generation, and API testing.
Key Concepts
OpenAPI Specification: A standard format (JSON/YAML) for describing REST API structure, endpoints, parameters, and responses.
Swagger UI: An interactive documentation interface generated from OpenAPI specs.
Schema: The structure definition of request/response bodies.
Real World Context
In production environments, OpenAPI documentation:
- Enables frontend developers to work in parallel with backend
- Auto-generates client SDKs in multiple languages
- Provides interactive testing without external tools
- Serves as a contract between teams
Deep Dive
Manual OpenAPI Schema
An OpenAPI spec is a structured dictionary describing your API's endpoints, parameters, request bodies, and response schemas:
python# openapi.py OPENAPI_SCHEMA = { 'openapi': '3.0.0', 'info': { 'title': 'My API', 'version': '1.0.0', 'description': 'API for managing articles' }, 'paths': { '/api/articles/': { 'get': { 'summary': 'List articles', 'parameters': [ {'name': 'page', 'in': 'query', 'schema': {'type': 'integer'}}, {'name': 'search', 'in': 'query', 'schema': {'type': 'string'}} ], 'responses': { '200': { 'description': 'List of articles', 'content': { 'application/json': { 'schema': {'$ref': '#/components/schemas/ArticleList'} } } } } }, 'post': { 'summary': 'Create article', 'requestBody': { 'content': { 'application/json': { 'schema': {'$ref': '#/components/schemas/ArticleCreate'} } } }, 'responses': { '201': {'description': 'Article created'} } } } }, 'components': { 'schemas': { 'Article': { 'type': 'object', 'properties': { 'id': {'type': 'integer'}, 'title': {'type': 'string'}, 'body': {'type': 'string'}, 'created_at': {'type': 'string', 'format': 'date-time'} } } } } }
The $ref values point to reusable component schemas, keeping the spec DRY when the same data structure appears in multiple endpoints.
Serving the Schema
Expose the spec as a JSON endpoint that tools like Swagger UI and client generators can consume:
python# views.py from django.http import JsonResponse from .openapi import OPENAPI_SCHEMA def openapi_schema(request): return JsonResponse(OPENAPI_SCHEMA) # urls.py urlpatterns = [ path('api/schema/', openapi_schema, name='api-schema'), ]
Clients and documentation tools fetch this endpoint to discover your API's structure automatically.
Auto-Generating Schema from Views (Pure Django)
You can build a schema generator that inspects your URL configuration and produces a valid OpenAPI spec without any third-party REST framework:
python# schema_generator.py import json import inspect from django.urls import get_resolver, URLPattern from django.http import JsonResponse def generate_openapi_schema(request): """Auto-generate OpenAPI schema from URL patterns.""" schema = { 'openapi': '3.0.0', 'info': { 'title': 'My API', 'version': '1.0.0', 'description': 'Auto-generated API documentation', }, 'paths': {}, 'servers': [ {'url': request.build_absolute_uri('/'), 'description': 'Current server'} ], } resolver = get_resolver() for pattern in resolver.url_patterns: if hasattr(pattern, 'url_patterns'): for sub in pattern.url_patterns: if isinstance(sub, URLPattern) and hasattr(sub.callback, 'schema_info'): path = '/' + str(pattern.pattern) + str(sub.pattern) schema['paths'][path] = sub.callback.schema_info return JsonResponse(schema) # Decorator to attach schema metadata to views def api_schema(method, summary, parameters=None, request_body=None, responses=None): def decorator(view_func): if not hasattr(view_func, 'schema_info'): view_func.schema_info = {} view_func.schema_info[method.lower()] = { 'summary': summary, 'parameters': parameters or [], 'responses': responses or {'200': {'description': 'Success'}}, } if request_body: view_func.schema_info[method.lower()]['requestBody'] = request_body return view_func return decorator
The @api_schema decorator attaches metadata to each view function. The generator then walks all URL patterns and collects this metadata into a valid OpenAPI document.
Serving Swagger UI with Static Files
You can serve the Swagger UI directly as a Django template:
python# views.py from django.shortcuts import render def swagger_ui(request): """Serve Swagger UI pointing to our schema endpoint.""" return render(request, 'swagger_ui.html', { 'schema_url': '/api/schema/', }) # urls.py urlpatterns = [ path('api/schema/', generate_openapi_schema, name='api-schema'), path('api/docs/', swagger_ui, name='api-docs'), ]
The template loads Swagger UI from a CDN and points it at your /api/schema/ endpoint, giving developers an interactive interface to explore and test your API.
Common Pitfalls
-
Outdated documentation: Auto-generate docs from code when possible to keep them in sync.
-
Missing examples: Include request/response examples for clarity.
-
Exposing internal APIs: Don't document internal endpoints meant only for your services.
Best Practices
- Auto-generate when possible: Use schema generators or decorators to keep docs in sync with code.
- Include examples: Show real request/response payloads.
- Document errors: Show possible error responses and their meanings.
- Version your docs: Documentation should match the API version.
Summary
OpenAPI provides a standardized way to document your API. Use auto-generation tools to keep docs in sync with code, include examples and error documentation, and serve interactive docs with Swagger UI for easy testing.
Code Examples
from django.http import JsonResponse
OPENAPI_SCHEMA = {
'openapi': '3.0.0',
'info': {'title': 'My API', 'version': '1.0.0'},
'paths': {
'/api/articles/': {
'get': {
'summary': 'List articles',
'responses': {'200': {'description': 'List of articles'}}
}
}
}
}
def openapi_schema(request):
return JsonResponse(OPENAPI_SCHEMA)