Skip to content

OpenAPI Documentation

Django-Bolt automatically generates OpenAPI documentation for your API. This guide covers how to configure and customize the documentation.

Accessing the documentation

By default, Django-Bolt serves multiple documentation UIs automatically:

Path UI
/docs Swagger UI (default)
/docs/redoc Redoc
/docs/scalar Scalar
/docs/rapidoc RapiDoc
/docs/stoplight Stoplight Elements
/docs/openapi.json Raw JSON schema
/docs/openapi.yaml Raw YAML schema

Start your server and visit any of these URLs to browse your API documentation.

Configuring OpenAPI

Customize the documentation using OpenAPIConfig:

from django_bolt import BoltAPI
from django_bolt.openapi import OpenAPIConfig

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        description="API for my application",
        enabled=True,
    )
)

Available options

OpenAPIConfig(
    title="My API",              # API title
    version="1.0.0",             # API version
    description="Description",   # API description
    enabled=True,                # Enable/disable docs
    docs_url="/docs",            # Swagger UI URL
    openapi_url="/openapi.json", # OpenAPI JSON URL
    django_auth=False,           # Enable Django admin auth for docs
)

Documenting endpoints

Summary and description

@api.get(
    "/users/{user_id}",
    summary="Get a user",
    description="Retrieve a user by their unique ID.",
    tags=["users"]
)
async def get_user(user_id: int):
    """
    This docstring also appears in the documentation.

    Additional details about the endpoint can go here.
    """
    return {"user_id": user_id}

Tags

Group endpoints using tags:

@api.get("/users", tags=["users"])
async def list_users():
    return []

@api.post("/users", tags=["users"])
async def create_user():
    return {}

@api.get("/articles", tags=["articles"])
async def list_articles():
    return []

Tags appear as sections in the Swagger UI.

Response models

Document response schemas:

import msgspec

class User(msgspec.Struct):
    id: int
    username: str
    email: str

@api.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    return {"id": user_id, "username": "john", "email": "john@example.com"}

The schema is automatically generated from the msgspec.Struct.

Request body schemas

Request bodies are documented automatically:

class CreateUser(msgspec.Struct):
    username: str
    email: str
    password: str

@api.post("/users")
async def create_user(user: CreateUser):
    return {"id": 1, "username": user.username}

Status codes

Document the default status code:

@api.post("/users", status_code=201)
async def create_user():
    return {"id": 1}

Customizing documentation UIs

By default, all documentation UIs are served automatically. To serve only specific UIs, provide a custom render_plugins list:

Swagger UI only

from django_bolt.openapi import OpenAPIConfig, SwaggerRenderPlugin

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        render_plugins=[SwaggerRenderPlugin(path="/")],
    )
)

ReDoc only

from django_bolt.openapi import OpenAPIConfig, RedocRenderPlugin

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        render_plugins=[RedocRenderPlugin(path="/")],
    )
)

Scalar only

from django_bolt.openapi import OpenAPIConfig, ScalarRenderPlugin

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        render_plugins=[ScalarRenderPlugin(path="/")],
    )
)

Stoplight Elements only

from django_bolt.openapi import OpenAPIConfig, StoplightRenderPlugin

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        render_plugins=[StoplightRenderPlugin(path="/")],
    )
)

RapiDoc only

from django_bolt.openapi import OpenAPIConfig, RapidocRenderPlugin

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        render_plugins=[RapidocRenderPlugin(path="/")],
    )
)

Multiple UIs at custom paths

from django_bolt.openapi import (
    OpenAPIConfig,
    SwaggerRenderPlugin,
    RedocRenderPlugin,
)

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        render_plugins=[
            SwaggerRenderPlugin(path="/"),      # /docs
            RedocRenderPlugin(path="/redoc"),   # /docs/redoc
        ],
    )
)

Raw OpenAPI JSON/YAML

The raw OpenAPI specification is always available at:

  • /docs/openapi.json - JSON format
  • /docs/openapi.yaml - YAML format (requires pyyaml package)

Protecting documentation

Django session authentication

Require Django user login to access docs (redirects to login page):

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        django_auth=True,  # Requires any logged-in Django user
    )
)

For staff-only access, use Django's staff_member_required:

from django.contrib.admin.views.decorators import staff_member_required

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        django_auth=staff_member_required,  # Requires staff user
    )
)

API-based authentication

Protect docs with JWT or API key authentication (returns 401/403 instead of redirects):

from django_bolt.auth import JWTAuthentication, IsAuthenticated

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        auth=[JWTAuthentication()],
        guards=[IsAuthenticated()],
    )
)

For staff-only API access:

from django_bolt.auth import JWTAuthentication, IsStaff

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        version="1.0.0",
        auth=[JWTAuthentication()],
        guards=[IsStaff()],
    )
)

Disabling documentation

Disable documentation in production:

import os

api = BoltAPI(
    openapi_config=OpenAPIConfig(
        title="My API",
        enabled=os.environ.get("DEBUG", "false").lower() == "true",
    )
)

Parameter documentation

Parameters are documented automatically from function signatures:

@api.get("/search")
async def search(
    q: str,           # Required query parameter
    page: int = 1,    # Optional with default
    limit: int = 20,  # Optional with default
):
    """
    Search for items.

    - **q**: Search query string (required)
    - **page**: Page number (default: 1)
    - **limit**: Items per page (default: 20)
    """
    return {"query": q, "page": page, "limit": limit}

Hiding endpoints

Exclude endpoints from documentation:

@api.get("/internal", include_in_schema=False)
async def internal():
    return {"internal": True}

OpenAPI extensions

The generated OpenAPI spec follows the OpenAPI 3.1.0 specification and includes:

  • Path parameters with types
  • Query parameters with defaults
  • Request body schemas from msgspec.Struct
  • Response schemas from response_model
  • Authentication requirements from auth= and guards=
  • Tag grouping
  • Operation summaries and descriptions