FastAPI Response Examples
When building APIs with FastAPI, providing clear documentation is essential for developers who will consume your API. One powerful feature that enhances documentation is the ability to include example responses. In this guide, we'll explore how to define and use response examples in FastAPI.
Introduction to Response Examples
Response examples show API users what data they can expect to receive from your endpoints. They appear in the auto-generated documentation (Swagger/OpenAPI UI) and help developers understand your API without having to make actual requests.
By providing examples, you can:
- Improve your API documentation
- Make it easier for others to integrate with your API
- Demonstrate different response scenarios
- Show the structure of complex response objects
Basic Response Examples
Using the example
Parameter
The simplest way to provide a response example is by using the example
parameter in your Pydantic model:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
id: int
name: str
email: str
is_active: bool
class Config:
schema_extra = {
"example": {
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"is_active": True
}
}
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
# Logic to fetch user from database
return {"id": user_id, "name": "John Doe", "email": "[email protected]", "is_active": True}
With this configuration, the Swagger UI documentation will show the example response for the /users/{user_id}
endpoint.
Using Field Examples
You can also specify examples for individual fields using the Field
function from Pydantic:
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class User(BaseModel):
id: int = Field(..., example=123)
name: str = Field(..., example="John Doe")
email: str = Field(..., example="[email protected]")
is_active: bool = Field(..., example=True)
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
# Logic to fetch user from database
return {"id": user_id, "name": "John Doe", "email": "[email protected]", "is_active": True}
Multiple Response Examples
Sometimes you want to show multiple examples for a single endpoint. FastAPI allows you to define multiple examples using the examples
parameter (note the plural):
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
id: int
name: str
email: str
is_active: bool
class Config:
schema_extra = {
"examples": [
{
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"is_active": True,
"summary": "Active user example"
},
{
"id": 456,
"name": "Jane Smith",
"email": "[email protected]",
"is_active": False,
"summary": "Inactive user example"
}
]
}
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
# Logic to fetch user from database
return {"id": user_id, "name": "John Doe", "email": "[email protected]", "is_active": True}
Response Examples with JSON Schema
For more control over examples, you can use the OpenAPI responses
parameter directly:
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi.responses import JSONResponse
app = FastAPI()
class User(BaseModel):
id: int
name: str
email: str
is_active: bool
@app.get(
"/users/{user_id}",
response_model=User,
responses={
200: {
"description": "Successful response",
"content": {
"application/json": {
"examples": {
"normal_user": {
"summary": "A normal user",
"value": {
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"is_active": True
}
},
"admin_user": {
"summary": "An admin user",
"value": {
"id": 999,
"name": "Admin User",
"email": "[email protected]",
"is_active": True
}
}
}
}
}
},
404: {
"description": "User not found",
"content": {
"application/json": {
"example": {"detail": "User not found"}
}
}
}
}
)
async def get_user(user_id: int):
# Logic to fetch user from database
return {"id": user_id, "name": "John Doe", "email": "[email protected]", "is_active": True}
This approach allows you to define examples for different response status codes and multiple examples per status code.
Real-world Example: Product API
Let's create a more comprehensive example for a product API with different response scenarios:
from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
app = FastAPI(title="Product API")
class ProductCategory(str, Enum):
ELECTRONICS = "electronics"
CLOTHING = "clothing"
BOOKS = "books"
HOME = "home"
class ProductResponse(BaseModel):
id: int = Field(..., example=1)
name: str = Field(..., example="Wireless Headphones")
price: float = Field(..., example=99.99)
category: ProductCategory = Field(..., example=ProductCategory.ELECTRONICS)
in_stock: bool = Field(..., example=True)
description: Optional[str] = Field(None, example="Noise-cancelling bluetooth headphones")
class Config:
schema_extra = {
"examples": {
"electronics": {
"summary": "Electronic product example",
"description": "A sample electronic product",
"value": {
"id": 1,
"name": "Wireless Headphones",
"price": 99.99,
"category": "electronics",
"in_stock": True,
"description": "Noise-cancelling bluetooth headphones"
}
},
"clothing": {
"summary": "Clothing product example",
"description": "A sample clothing product",
"value": {
"id": 2,
"name": "Cotton T-Shirt",
"price": 19.99,
"category": "clothing",
"in_stock": True,
"description": "100% organic cotton t-shirt"
}
},
"out_of_stock": {
"summary": "Out of stock product",
"description": "A product that is currently unavailable",
"value": {
"id": 3,
"name": "Bestselling Novel",
"price": 24.99,
"category": "books",
"in_stock": False,
"description": "The latest bestseller from a renowned author"
}
}
}
}
class ProductListResponse(BaseModel):
count: int
products: List[ProductResponse]
class Config:
schema_extra = {
"example": {
"count": 2,
"products": [
{
"id": 1,
"name": "Wireless Headphones",
"price": 99.99,
"category": "electronics",
"in_stock": True,
"description": "Noise-cancelling bluetooth headphones"
},
{
"id": 2,
"name": "Cotton T-Shirt",
"price": 19.99,
"category": "clothing",
"in_stock": True,
"description": "100% organic cotton t-shirt"
}
]
}
}
@app.get(
"/products/{product_id}",
response_model=ProductResponse,
responses={
404: {
"description": "Product not found",
"content": {
"application/json": {
"example": {"detail": "Product with ID 123 not found"}
}
}
}
}
)
async def get_product(product_id: int):
"""
Get detailed information about a specific product by its ID.
- **product_id**: The unique identifier of the product
"""
# In a real app, this would fetch data from a database
if product_id > 1000:
raise HTTPException(status_code=404, detail=f"Product with ID {product_id} not found")
return {
"id": product_id,
"name": "Sample Product",
"price": 29.99,
"category": "electronics",
"in_stock": True,
"description": "This is a sample product"
}
@app.get(
"/products/",
response_model=ProductListResponse
)
async def list_products(
category: Optional[ProductCategory] = None,
min_price: Optional[float] = None,
max_price: Optional[float] = None,
in_stock: Optional[bool] = Query(None, description="Filter by availability")
):
"""
List all products with optional filtering.
"""
# In a real app, this would query a database with filters
products = [
{
"id": 1,
"name": "Wireless Headphones",
"price": 99.99,
"category": "electronics",
"in_stock": True,
"description": "Noise-cancelling bluetooth headphones"
},
{
"id": 2,
"name": "Cotton T-Shirt",
"price": 19.99,
"category": "clothing",
"in_stock": True,
"description": "100% organic cotton t-shirt"
}
]
return {"count": len(products), "products": products}
In this example, we've created a more comprehensive API with:
- Multiple examples for different product categories
- Response examples for error cases
- Structured documentation that clearly shows what users should expect
Response Examples with Different Status Codes
FastAPI allows you to define examples for different HTTP status codes. This is particularly useful for error handling:
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
username: str
email: str
full_name: str
class ErrorResponse(BaseModel):
detail: str
@app.get(
"/users/{username}",
response_model=User,
responses={
200: {
"description": "User found",
"content": {
"application/json": {
"example": {
"username": "johndoe",
"email": "[email protected]",
"full_name": "John Doe"
}
}
}
},
404: {
"model": ErrorResponse,
"description": "User not found",
"content": {
"application/json": {
"example": {"detail": "User not found"}
}
}
},
401: {
"model": ErrorResponse,
"description": "Unauthorized access",
"content": {
"application/json": {
"example": {"detail": "Not authenticated"}
}
}
}
}
)
async def get_user(username: str):
if username != "johndoe":
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found"
)
return {"username": "johndoe", "email": "[email protected]", "full_name": "John Doe"}
Best Practices for Response Examples
- Make examples realistic - Use data that looks like what your API actually returns.
- Include examples for error responses - Not just successful ones.
- Show different variations - If your endpoint can return different structures, show examples of each.
- Keep examples concise - They should be comprehensive but not overwhelming.
- Update examples when your API changes - Outdated examples are worse than no examples.
- Use meaningful values - Avoid placeholder values like "foo" or "bar" when possible.
- Add descriptions to examples - Explain what scenario each example represents.
Summary
Response examples are a powerful way to enhance your FastAPI documentation. They help API consumers understand what to expect from your endpoints without having to make actual requests. By providing examples for different scenarios and status codes, you make your API more accessible and user-friendly.
FastAPI offers multiple ways to define response examples:
- Using the
example
parameter for single examples - Using
Field()
for field-level examples - Using the
examples
parameter for multiple examples - Using the OpenAPI
responses
parameter for fine-grained control
With these tools, you can create comprehensive documentation that makes your API easier to understand and use.
Additional Resources
- FastAPI Official Documentation on Response Model
- OpenAPI Specification
- Pydantic Schema Customization
Exercises
- Create a FastAPI endpoint that returns a list of blog posts with at least three different example responses.
- Implement an API endpoint with multiple possible status codes (200, 400, 401, 404) and add appropriate examples for each.
- Build a nested response model (e.g., an order with line items) and provide examples that show different variations of the data.
- Practice updating your Swagger documentation with examples and test the "Try it out" functionality to see how examples appear in the documentation.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)