FastAPI Automatic Docs
One of the most powerful features of FastAPI is its ability to automatically generate interactive documentation for your API. This means you don't have to manually document your endpoints or maintain separate documentation that might become outdated - FastAPI does this work for you!
Introduction
When you build an API with FastAPI, the framework automatically creates two different interactive documentation interfaces:
- Swagger UI - A user-friendly interface that allows you to view and test your API endpoints
- ReDoc - An alternative documentation viewer with a different layout and features
Both documentation systems are automatically generated from the same OpenAPI schema that FastAPI creates based on your code, type hints, and docstrings.
How It Works
FastAPI leverages Python type hints and the Pydantic library to:
- Validate incoming requests
- Convert data types
- Generate OpenAPI schema documentation
The framework analyzes your route functions, their parameters, return types, and docstrings to build a comprehensive API specification.
Accessing the Automatic Documentation
When you run a FastAPI application, two documentation endpoints are automatically available:
/docs
- Swagger UI (interactive)/redoc
- ReDoc (alternative documentation)
Let's create a simple FastAPI application and see the documentation in action:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
"""Return a greeting message."""
return {"message": "Hello World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
"""
Fetch an item by its ID.
- **item_id**: The ID of the item to retrieve
- **q**: Optional query parameter
"""
return {"item_id": item_id, "q": q}
After starting the application (using uvicorn main:app --reload
), you can visit:
http://127.0.0.1:8000/docs
for Swagger UIhttp://127.0.0.1:8000/redoc
for ReDoc
Enhancing Documentation with Metadata
FastAPI uses the information you provide in your code to create rich documentation. Here are ways to enhance it:
1. Function Docstrings
Docstrings in your route functions are displayed in the documentation:
@app.get("/users/{user_id}")
def read_user(user_id: int):
"""
Retrieve a user by id.
This endpoint returns user information based on the provided user ID.
If the user doesn't exist, it will return a 404 error.
"""
return {"user_id": user_id}
2. Parameter Descriptions with Pydantic
For more complex input data, use Pydantic models with field descriptions:
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI()
class Item(BaseModel):
name: str = Field(..., description="The name of the item")
price: float = Field(..., description="The price of the item in USD")
is_offer: Optional[bool] = Field(None, description="Whether the item is currently on offer")
tags: list[str] = Field(default=[], description="Tags associated with the item")
@app.post("/items/")
def create_item(item: Item):
"""Create a new item in the database."""
return item
3. Response Models
Define response models to document what your API returns:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserResponse(BaseModel):
id: int
username: str
email: str
is_active: bool
@app.get("/users/me", response_model=UserResponse)
def read_current_user():
"""Get information about the currently logged in user."""
return {
"id": 1,
"username": "johndoe",
"email": "[email protected]",
"is_active": True
}
4. Status Codes and Responses
Document different response types:
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.get(
"/items/{item_id}",
responses={
200: {"description": "Item found"},
404: {"description": "Item not found"},
500: {"description": "Internal server error"}
}
)
def get_item(item_id: int):
"""
Get an item by ID with documented response codes.
"""
if item_id == 0:
raise HTTPException(status_code=404, detail="Item not found")
return {"id": item_id, "name": "Sample item", "price": 19.99}
Customizing API Documentation
You can customize the documentation by providing metadata when initializing your FastAPI application:
from fastapi import FastAPI
app = FastAPI(
title="My Super API",
description="This API does awesome things",
version="0.1.0",
terms_of_service="http://example.com/terms/",
contact={
"name": "API Support",
"url": "http://www.example.com/support",
"email": "[email protected]",
},
license_info={
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
},
)
@app.get("/")
def read_root():
return {"Hello": "World"}
Tags for Organization
You can use tags to group related endpoints:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/", tags=["users"])
def get_users():
"""List all users in the system."""
return [{"username": "johndoe"}, {"username": "alice"}]
@app.post("/users/", tags=["users"])
def create_user():
"""Create a new user."""
return {"username": "new_user"}
@app.get("/items/", tags=["items"])
def get_items():
"""List all items in the system."""
return [{"name": "Hammer"}, {"name": "Pliers"}]
Advanced: OpenAPI Schema Customization
For advanced customization, you can directly modify the OpenAPI schema:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
# Customize OpenAPI schema after defining all routes
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom API Doc Title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
# Add custom documentation here
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
Disabling Docs
If needed, you can disable automatic documentation:
from fastapi import FastAPI
# Disable both documentation interfaces
app = FastAPI(docs_url=None, redoc_url=None)
@app.get("/")
def read_root():
return {"Hello": "World"}
Or disable just one:
# Disable only Redoc
app = FastAPI(redoc_url=None)
Real-World Example: Product API
Let's put everything together in a more complete example of a product API:
from fastapi import FastAPI, HTTPException, Query, Path
from pydantic import BaseModel, Field
from typing import Optional, List
from enum import Enum
# Create app with custom metadata
app = FastAPI(
title="Product Management API",
description="API for managing an online store's product inventory",
version="1.0.0",
)
# Define product category enum
class Category(str, Enum):
electronics = "electronics"
clothing = "clothing"
books = "books"
home = "home"
other = "other"
# Define data models
class ProductBase(BaseModel):
name: str = Field(..., description="Name of the product", example="Wireless Headphones")
price: float = Field(..., gt=0, description="Price in USD", example=99.99)
description: Optional[str] = Field(None, description="Product description")
category: Category = Field(..., description="Product category")
in_stock: bool = Field(True, description="Whether the product is in stock")
class ProductCreate(ProductBase):
"""Schema for creating a new product."""
pass
class ProductResponse(ProductBase):
"""Schema for API responses including product data."""
id: int = Field(..., description="Unique product identifier")
class Config:
schema_extra = {
"example": {
"id": 1,
"name": "Bluetooth Speaker",
"price": 49.99,
"description": "Portable wireless speaker with deep bass",
"category": "electronics",
"in_stock": True
}
}
# Mock database
products_db = [
{
"id": 1,
"name": "Bluetooth Speaker",
"price": 49.99,
"description": "Portable wireless speaker with deep bass",
"category": "electronics",
"in_stock": True
}
]
# Routes with tags for organization
@app.get(
"/products/",
response_model=List[ProductResponse],
tags=["products"],
summary="List all products",
response_description="List of products"
)
def get_products(
skip: int = Query(0, description="Number of products to skip"),
limit: int = Query(10, le=100, description="Max number of products to return"),
category: Optional[Category] = Query(None, description="Filter by category")
):
"""
Retrieve a list of products with optional filtering.
- **skip**: Number of products to skip (pagination)
- **limit**: Maximum number of products to return
- **category**: Optional filter by product category
"""
if category:
filtered_products = [p for p in products_db if p["category"] == category]
return filtered_products[skip: skip + limit]
return products_db[skip: skip + limit]
@app.get(
"/products/{product_id}",
response_model=ProductResponse,
tags=["products"],
responses={
200: {"description": "Product found"},
404: {"description": "Product not found"}
}
)
def get_product(
product_id: int = Path(..., title="Product ID", description="The ID of the product to retrieve", ge=1)
):
"""
Retrieve a single product by its ID.
- **product_id**: Unique identifier of the product
"""
for product in products_db:
if product["id"] == product_id:
return product
raise HTTPException(status_code=404, detail=f"Product with ID {product_id} not found")
@app.post(
"/products/",
response_model=ProductResponse,
status_code=201,
tags=["products"],
summary="Create a new product"
)
def create_product(product: ProductCreate):
"""
Create a new product in the database.
The request body must contain the product details.
Returns the created product with its assigned ID.
"""
new_id = max(p["id"] for p in products_db) + 1 if products_db else 1
new_product = product.dict()
new_product["id"] = new_id
products_db.append(new_product)
return new_product
Summary
FastAPI's automatic documentation feature is one of its strongest selling points. It allows you to:
- Create interactive, always up-to-date API documentation with minimal effort
- Test your API endpoints directly from the browser
- Provide clear information to API consumers
- Ensure your API design is well-structured and coherent
The documentation is driven by:
- Python type hints
- Pydantic models
- Function docstrings
- Parameter descriptions
- Custom metadata
By following best practices for documenting your FastAPI application, you can create professional, user-friendly APIs that are easy to understand and use.
Additional Resources
Exercises
- Create a simple FastAPI application with at least three endpoints and view the automatic documentation.
- Add detailed descriptions to your endpoints using docstrings and Pydantic Field descriptions.
- Organize your API using tags and customize the OpenAPI metadata.
- Create a complex API with multiple response models and different status codes.
- Try disabling one documentation interface while keeping the other active.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)