404 Not Found

404 Not Found


nginx

API Documentation and OpenAPI Customization — Creating Professional API Documentation

API documentation is like a product manual—without it, customers (developers) won't use your product; if it's poorly written, customers will vote with their feet. Automated documentation generation is FastAPI's secret weapon, but the default configuration is just the starting point; customization is what sets the pros apart.

1. What You'll Learn


2. Alice's True Story

(1) Pain Point: The default documentation isn't professional enough

Alice's PriceTracker API documentation uses FastAPI's default Swagger UI, where all endpoints are mixed together without being grouped, so Bob can't find the endpoint he needs. To make matters worse, the documentation lacks sample requests, so Bob doesn't know what value to enter for the currency field; there's no versioning for request or response bodies; and new and deprecated endpoints are all mixed together.

(2) Custom Solutions for OpenAPI

FastAPI allows for deep customization of OpenAPI documentation—including tag grouping, example values, deprecation markers, and custom schemas—transforming API documentation from merely "readable" to "usable."

(3) Revenue

Bob can simply open the documentation to quickly locate endpoints by tag (Products/Prices/Auth). Sample values eliminate the need to guess when making requests, and deprecated endpoints are marked in gray to prevent accidental use. As a result, the quality of the documentation has been upgraded from "internal reference" to "public release" level.


3. Swagger UI and ReDoc Configuration

(1) OpenAPI Generation Process

100%
flowchart LR
    A[FastAPI Routes] --> B[Pydantic Models]
    B --> C[OpenAPI 3.1 Schema]
    C --> D[Swagger UI /docs]
    C --> E[ReDoc /redoc]
    C --> F[Raw JSON /openapi.json]

(1) ▶ Example: FastAPI Application-Level Documentation Configuration

PYTHON
from fastapi import FastAPI

app = FastAPI(
    title="PriceTracker API",
    description="""
    ## PriceTracker SaaS API
    
    E-commerce price tracking service for monitoring million-level product prices.
    
    ### (1) Authentication
    All protected endpoints require a Bearer token obtained from `/auth/login`.
    
    ### (2) Rate Limits
    - Free: 100 requests/min
    - Pro: 1000 requests/min
    - Enterprise: unlimited
    """,
    version="1.0.0",
    terms_of_service="https://pricetracker.example.com/terms",
    contact={
        "name": "PriceTracker Support",
        "url": "https://pricetracker.example.com/support",
        "email": "support@pricetracker.example.com",
    },
    license_info={
        "name": "MIT License",
        "url": "https://opensource.org/licenses/MIT",
    },
    docs_url="/docs",
    redoc_url="/redoc",
    openapi_url="/openapi.json",
)

Output:

TEXT
# Execution Successful

(3) ▶ Example: Customizing Swagger UI Parameters

PYTHON
app = FastAPI(
    swagger_ui_parameters={
        "persistAuthorization": True,  # Keep auth between page refreshes
        "displayRequestDuration": True,  # Show request duration
        "filter": True,  # Enable search filter
        "syntaxHighlight.theme": "monokai",  # Code highlighting theme
        "defaultModelsExpandDepth": 1,  # Expand models 1 level deep
        "defaultModelExpandDepth": 1,
    }
)

Output:

TEXT
# Execution Successful
Parameter Default Description
persistAuthorization False Refresh page while retaining authentication
displayRequestDuration False Show request duration
filter False Enable Search Filter
defaultModelsExpandDepth 1 Model Unfolding Depth
syntaxHighlight.theme "agate" Code Highlighting Theme

4. Tag Grouping and Deprecation Markers

(1) Tags: Grouped Endpoints

(1) ▶ Example: Defining Tags

PYTHON
from fastapi import FastAPI, APIRouter

tags_metadata = [
    {
        "name": "auth",
        "description": "Authentication operations. Login, register, token refresh.",
    },
    {
        "name": "products",
        "description": "Product management. CRUD operations for tracked products.",
    },
    {
        "name": "prices",
        "description": "Price data. Query, import, and track price changes.",
    },
    {
        "name": "admin",
        "description": "Admin operations. Requires admin role.",
    },
]

app = FastAPI(
    title="PriceTracker API",
    openapi_tags=tags_metadata,
)

Output:

TEXT
# Execution Successful

(2) ▶ Example: Endpoint Assignment Tags

PYTHON
@app.post("/auth/login", tags=["auth"])
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    ...

@app.get("/api/v1/products", tags=["products"])
async def list_products():
    ...

@app.post("/api/v1/prices", tags=["prices"])
async def create_price():
    ...

@app.get("/api/v1/admin/stats", tags=["admin"])
async def admin_stats():
    ...

Output:

TEXT
# Function defined successfully

(3) ▶ Example: Marking an endpoint as deprecated

PYTHON
@app.get(
    "/api/v1/products/{product_id}/history",
    tags=["prices"],
    deprecated=True,
    summary="[DEPRECATED] Use GET /prices?product_id={id} instead",
)
async def get_price_history_deprecated(product_id: int):
    """This endpoint is deprecated. Use the prices endpoint with product_id filter."""
    ...

Output:

TEXT
# Function defined successfully

5. Sample Values and Response Templates

(1) json_schema_extra and examples

(1) ▶ Example: Sample values for Pydantic models

PYTHON
from pydantic import BaseModel, Field

class ProductCreate(BaseModel):
    name: str = Field(
        min_length=1, max_length=200,
        description="Product display name",
        examples=["Wireless Mouse", "USB-C Hub", "Mechanical Keyboard"],
    )
    category: str = Field(
        max_length=100,
        description="Product category",
        examples=["electronics", "clothing", "food"],
    )
    base_price: float = Field(
        gt=0,
        description="Base price in USD",
        examples=[9.99, 49.99, 199.99],
    )

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Wireless Mouse",
                    "category": "electronics",
                    "base_price": 29.99,
                }
            ]
        }
    }

Output:

TEXT
# Execution Successful

(2) ▶ Example: Example of an endpoint-level response

PYTHON
from fastapi import FastAPI
from fastapi.responses import JSONResponse

@app.post(
    "/api/v1/products",
    response_model=ProductResponse,
    status_code=201,
    summary="Create a new product",
    description="Create a new product in the PriceTracker database.",
    responses={
        201: {
            "description": "Product created successfully",
            "content": {
                "application/json": {
                    "example": {
                        "id": 1,
                        "name": "Wireless Mouse",
                        "category": "electronics",
                        "base_price": 29.99,
                    }
                }
            },
        },
        401: {"description": "Authentication required"},
        403: {"description": "Insufficient permissions"},
        422: {"description": "Validation error"},
    },
)
async def create_product(product: ProductCreate):
    ...

Output:

TEXT
# Function defined successfully

6. Custom OpenAPI Schema

(1) generate_unique_id_function

(1) ▶ Example: Generating a Custom Endpoint ID

PYTHON
from fastapi import FastAPI

def custom_generate_unique_id(route):
    # Format: {method}_{tag}_{path}
    tags = route.tags or ["default"]
    tag = tags[0]
    method = route.methods.pop() if route.methods else "GET"
    path = route.path.replace("/", "_").strip("_").replace("{", "").replace("}", "")
    return f"{method}_{tag}_{path}"

app = FastAPI(
    generate_unique_id_function=custom_generate_unique_id,
)

Output:

TEXT
# Function defined successfully

(2) Comparison of Documentation Best Practices

Dimension Default Best Practice
Endpoint Groups None Tags by Function
Abandoned endpoints Mixed in with normal endpoints deprecated=True Gray mark
Request Example None examples + json_schema_extra
Response Templates 200 Only Full Coverage for 201/401/403/422
Description Simple Function Name Summary + Description
Certification Information None Documentation Home Page: Explanation of Certification Methods
Versioning Single Version URL Path Version /api/v1/

❓ FAQ

Q What is the difference between Swagger UI and ReDoc?
A Swagger UI is interactive (allows you to test APIs), while ReDoc is designed for reading (more visually appealing). We recommend ReDoc for external documentation and Swagger UI for internal development.
Q How can I hide certain endpoints so they don't appear in the documentation?
A Set include_in_schema=False:@app.get("/internal", include_in_schema=False). This is suitable for internal health checks and monitoring endpoints.
Q Should I use OpenAPI version 3.0 or 3.1?
A FastAPI generates OpenAPI 3.1 by default (which supports the latest JSON Schema features). If you need compatibility with older tools, you can downgrade the version in the custom openapi function.
Q How do I add custom CSS/JS to a document?
A Use swagger_ui_parameters to provide a CSS URL, or use get_swagger_ui_html to fully customize the HTML.
Q What is the difference between example values and default values?
A "examples" are for documentation purposes and do not affect validation; "default" are the actual default values that affect behavior. Both should be set.
Q How should documentation for multiple API versions be organized?
A Use a separate APIRouter(prefix="/api/v1") for each version and distinguish between versions using tags. Alternatively, create a separate FastAPI sub-application for each version.

📖 Summary


📝 Exercises

  1. Basic Question (Difficulty ⭐): Configure the FastAPI application-level documentation for PriceTracker—including the title, description, version number, and contact information—and add persistAuthorization=True to ensure Swagger UI retains the authentication status. Hint: FastAPI(title=..., swagger_ui_parameters={...})
  2. Advanced Exercise (Difficulty ⭐⭐): Define 4 tags (auth/products/prices/admin), assign the correct tag to each endpoint, mark the deprecated endpoint deprecated=True, and verify that the endpoints are grouped by tag in Swagger UI. Hint: openapi_tags=[...] + tags=["products"]
  3. Challenge (Difficulty: ⭐⭐⭐): Add a complete example of json_schema_extra to ProductCreate, and add response templates for status codes 201, 401, 403, and 422 (including sample content) to the POST /products endpoint to implement the custom generate_unique_id_function. Hint: responses={201: {"content": {...}}} + generate_unique_id_function

---|

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏