FastAPI Interactive Documentation
Introduction
One of FastAPI's most powerful features is its automatic interactive API documentation. When you build an API with FastAPI, you get not just one, but two different interactive documentation interfaces for free: Swagger UI and ReDoc. These tools allow developers to visualize and interact with your API's endpoints without having to write any additional code or use external tools like Postman.
In this tutorial, we'll explore how FastAPI generates this documentation, how to access it, customize it, and use it effectively during development.
Understanding FastAPI's Documentation Systems
FastAPI provides two documentation interfaces out of the box:
- Swagger UI - A rich interactive interface where you can explore, test and understand your API
- ReDoc - A responsive, well-organized alternative documentation interface
Both of these interfaces are automatically generated from your API's OpenAPI schema (formerly known as Swagger), which FastAPI also generates automatically based on your code.
Accessing the Documentation
Let's start with a basic FastAPI application and see how to access the documentation:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
After running this application with Uvicorn:
uvicorn main:app --reload
You can access the documentation at:
- Swagger UI:
http://127.0.0.1:8000/docs
- ReDoc:
http://127.0.0.1:8000/redoc
Exploring Swagger UI
When you navigate to the /docs
endpoint, you'll see the Swagger UI interface that looks like this:
Key features of Swagger UI include:
1. API Overview
At the top, you'll see general information about your API, including its title, description, and version.
2. Endpoints Grouped by Tags
All your endpoints are listed, organized by tags (which we'll learn to customize later).
3. Interactive Testing
For each endpoint, you can:
- Click on it to expand details
- Click the "Try it out" button
- Fill in parameters
- Execute the request
- See the response directly in the browser
Let's test our /items/{item_id}
endpoint:
- Click on the endpoint to expand it
- Click "Try it out" button
- Enter a value for
item_id
(e.g.,42
) - Optionally enter a value for query parameter
q
(e.g.,test-query
) - Click "Execute"
You'll see:
- The curl command that was generated
- The request URL
- The server response with status code
- The response body showing:
{"item_id": 42, "q": "test-query"}
This interactive testing capability is invaluable during development and for helping other developers understand how to use your API.
Working with ReDoc
ReDoc offers a more streamlined, documentation-focused interface. Navigate to /redoc
to see it:
ReDoc features:
- Clean, three-panel layout
- Automatic request/response examples
- Search functionality
- Mobile-friendly design
While ReDoc doesn't offer the interactive testing capabilities of Swagger UI, it provides excellent documentation that can be more approachable for non-technical stakeholders.
Enhancing Your Documentation
Now let's explore how to improve your API documentation through various FastAPI features.
Adding Operation Descriptions
You can add descriptions to your endpoints using docstrings:
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
"""
Fetch an item by its ID.
- **item_id**: The unique identifier for the item
- **q**: Optional query string for filtering results
"""
return {"item_id": item_id, "q": q}
These descriptions will appear in both Swagger UI and ReDoc.
Using Tags for Organization
As your API grows, organizing endpoints becomes important. Tags help group related endpoints:
@app.get("/users/", tags=["users"])
def get_users():
return [{"name": "Jane"}, {"name": "John"}]
@app.post("/users/", tags=["users"])
def create_user(name: str):
return {"name": name}
@app.get("/items/", tags=["items"])
def get_items():
return [{"name": "Item 1"}, {"name": "Item 2"}]
Now in the documentation, you'll see endpoints grouped under "users" and "items" categories.
Adding Example Responses
You can provide example responses in your documentation:
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import List
app = FastAPI()
class Item(BaseModel):
id: int
name: str
description: str = None
price: float
tax: float = None
class Config:
schema_extra = {
"example": {
"id": 1,
"name": "Smartphone",
"description": "Latest model with high-res camera",
"price": 799.99,
"tax": 79.99
}
}
@app.post("/items/")
def create_item(item: Item):
return item
The schema_extra
with its example
provides sample data in the documentation.
Customizing API Metadata
You can customize the title, description, version, and other metadata for your API:
app = FastAPI(
title="My Super API",
description="This is a very fancy API that does awesome stuff",
version="0.1.0",
terms_of_service="http://example.com/terms/",
contact={
"name": "API Support",
"url": "http://example.com/support",
"email": "[email protected]",
},
license_info={
"name": "MIT License",
"url": "https://opensource.org/licenses/MIT",
},
)
This information appears at the top of your documentation pages.
Real-World Example: Building a Todo API with Detailed Documentation
Let's create a more complete example of a Todo API with well-documented endpoints:
from fastapi import FastAPI, HTTPException, Query, Path, Body
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
app = FastAPI(
title="Todo API",
description="A simple API for managing your todos",
version="1.0.0"
)
class PriorityLevel(str, Enum):
low = "low"
medium = "medium"
high = "high"
class TodoBase(BaseModel):
title: str = Field(..., example="Buy groceries")
description: Optional[str] = Field(None, example="Milk, Eggs, Bread")
priority: PriorityLevel = Field(default=PriorityLevel.medium, example="high")
class TodoCreate(TodoBase):
pass
class Todo(TodoBase):
id: int = Field(..., example=1)
completed: bool = Field(default=False, example=False)
class Config:
schema_extra = {
"example": {
"id": 1,
"title": "Buy groceries",
"description": "Milk, Eggs, Bread",
"priority": "high",
"completed": False
}
}
# In-memory database
todos = {}
todo_id_counter = 1
@app.post("/todos/", response_model=Todo, status_code=201, tags=["todos"])
def create_todo(todo: TodoCreate):
"""
Create a new todo item.
This endpoint allows you to create a new todo item with the given details.
The todo ID will be assigned automatically.
"""
global todo_id_counter
new_todo = Todo(
id=todo_id_counter,
**todo.dict()
)
todos[todo_id_counter] = new_todo
todo_id_counter += 1
return new_todo
@app.get("/todos/", response_model=List[Todo], tags=["todos"])
def read_todos(
skip: int = Query(0, description="Skip N items", ge=0),
limit: int = Query(10, description="Limit the number of items returned", ge=1, le=100),
priority: Optional[PriorityLevel] = Query(None, description="Filter by priority level")
):
"""
Get all todos with optional filtering.
You can paginate results using skip and limit parameters,
and filter by priority if needed.
"""
result = list(todos.values())
if priority:
result = [todo for todo in result if todo.priority == priority]
return result[skip:skip+limit]
@app.get("/todos/{todo_id}", response_model=Todo, tags=["todos"])
def read_todo(
todo_id: int = Path(..., description="The ID of the todo to retrieve", ge=1)
):
"""
Get a specific todo by ID.
Retrieves the details of a specific todo item by its unique identifier.
"""
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
return todos[todo_id]
@app.put("/todos/{todo_id}", response_model=Todo, tags=["todos"])
def update_todo(
todo_id: int = Path(..., description="The ID of the todo to update", ge=1),
todo: TodoCreate = Body(..., description="Updated todo information")
):
"""
Update a todo.
Updates the details of an existing todo item. All fields will be replaced.
"""
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
updated_todo = Todo(
id=todo_id,
completed=todos[todo_id].completed,
**todo.dict()
)
todos[todo_id] = updated_todo
return updated_todo
@app.patch("/todos/{todo_id}/complete", response_model=Todo, tags=["todos"])
def complete_todo(
todo_id: int = Path(..., description="The ID of the todo to mark as complete", ge=1)
):
"""
Mark a todo as complete.
This is a convenience endpoint to toggle a todo's completed status to true.
"""
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
todos[todo_id].completed = True
return todos[todo_id]
@app.delete("/todos/{todo_id}", status_code=204, tags=["todos"])
def delete_todo(
todo_id: int = Path(..., description="The ID of the todo to delete", ge=1)
):
"""
Delete a todo.
Permanently removes a todo item from the system.
"""
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
del todos[todo_id]
return None
This example demonstrates:
- Detailed API metadata
- Enum for constrained values
- Rich documentation with examples
- Proper response models and status codes
- Parameter validation and descriptions
- Organized endpoints with tags
- Comprehensive docstrings
Disabling Documentation
In some cases, you might want to disable the interactive documentation for production environments:
app = FastAPI(docs_url=None, redoc_url=None)
This removes both the Swagger UI and ReDoc interfaces. You can also disable just one:
app = FastAPI(redoc_url=None) # Disables only ReDoc
Summary
FastAPI's interactive documentation is one of its strongest features, providing:
- Automatic generation of OpenAPI schema from your code
- Two different interactive documentation interfaces (Swagger UI and ReDoc)
- The ability to test your API directly from the browser
- Customization options for improving documentation quality
- Tools to organize endpoints as your API grows
This documentation not only serves as a valuable development tool but also provides clear, up-to-date documentation for API consumers with zero additional effort.
Additional Resources
- FastAPI Official Documentation on Interactive Docs
- OpenAPI Specification
- Swagger UI Documentation
- ReDoc Documentation
Practice Exercises
- Create a basic FastAPI application and experiment with both documentation interfaces
- Try enhancing your API documentation with detailed descriptions and examples
- Build an API with at least 5 endpoints, organizing them with appropriate tags
- Create custom response models with examples for all your endpoints
- Try customizing the API metadata with your own information
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)