Skip to main content

FastAPI Operation Description

Introduction

When building an API, documentation is crucial for both your future self and other developers who will use your API. FastAPI provides several ways to document your API endpoints, and one of the most useful features is the ability to add detailed descriptions to your operations (routes/endpoints).

In this guide, we'll explore how to add descriptions to your FastAPI endpoints, why they're important, and how they appear in the automatically generated interactive documentation.

Why Add Descriptions to API Endpoints?

Before diving into the how, let's understand why adding descriptions to your API endpoints is beneficial:

  • Clarity: It helps users understand the purpose of each endpoint
  • Usage guidance: You can explain expected inputs and outputs
  • Troubleshooting: You can document common errors and their solutions
  • Examples: You can provide usage examples directly in the documentation
  • Maintenance: Makes it easier for you or other developers to maintain the code

Basic Endpoint Description

The simplest way to add a description to a FastAPI endpoint is through the summary and description parameters in the path operation decorator.

python
from fastapi import FastAPI

app = FastAPI()

@app.get(
"/users/",
summary="List all users",
description="Get a list of all registered users in the system. The results can be filtered by status and role."
)
def get_users():
return [{"name": "John Doe"}, {"name": "Jane Smith"}]

When you visit the automatic documentation at /docs, you'll see this summary and description displayed for the endpoint:

Using Docstrings for Descriptions

A more Pythonic approach is to use docstrings for your endpoint descriptions. FastAPI will automatically use your function's docstring as the description if you don't specify the description parameter:

python
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/", summary="Get all items")
async def get_items():
"""
Retrieve all items from the database.

This endpoint returns a list of all items with their:
- ID
- Name
- Price
- Stock status

The items are sorted by ID in ascending order.
"""
return [{"id": 1, "name": "Item 1"}]

This approach keeps your documentation close to your code and follows Python best practices.

Multi-line Descriptions

For complex endpoints, you might want to provide more detailed descriptions. You can use multi-line strings for this:

python
from fastapi import FastAPI

app = FastAPI()

@app.post(
"/orders/",
summary="Create an order",
description="""
Create a new order in the system. The order will be:

* Validated against inventory
* Reserved in the database
* Payment will be processed
* Confirmation email will be sent

If the payment fails, the order will be automatically cancelled.
"""
)
async def create_order(order_id: str):
return {"order_id": order_id, "status": "created"}

Markdown in Descriptions

One of the powerful features of FastAPI is that it supports Markdown in descriptions, which allows for rich formatting:

python
from fastapi import FastAPI

app = FastAPI()

@app.get("/products/{product_id}")
async def get_product(product_id: int):
"""
# Product Details

Returns detailed information about a specific product.

## Response Format

{
"id": 1,
"name": "Example Product",
"price": 29.99,
"description": "This is an example product",
"in_stock": true
}


## Error Responses

| Status Code | Description |
| ----------- | ----------- |
| 404 | Product not found |
| 500 | Server error |

"""
return {"id": product_id, "name": "Example Product"}

When rendered in the documentation, this will show formatted headings, code blocks, and even tables.

Description vs. Response Model

While descriptions help explain what an endpoint does, you should also use response models to define the structure of your responses:

python
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI()

class User(BaseModel):
id: int
name: str
email: str
active: bool = True

@app.get(
"/users/{user_id}",
response_model=User,
summary="Get user details",
description="Retrieve detailed information about a specific user by their ID."
)
async def get_user(user_id: int):
"""
Fetch a user from the database by their ID.

- If the user exists, their details are returned
- If no user is found with that ID, a 404 error is returned
"""
# In a real app, you'd fetch from a database
return {"id": user_id, "name": "John Doe", "email": "[email protected]", "active": True}

This combination of description and response model gives users of your API both narrative and structural documentation.

Practical Example: Building a Book API

Let's create a more complete example showing descriptions in a real-world application:

python
from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI(
title="BookStore API",
description="API for managing a bookstore's inventory and sales",
version="1.0.0"
)

class Book(BaseModel):
id: int
title: str
author: str
price: float
in_stock: bool

# Our "database"
books_db = [
{"id": 1, "title": "FastAPI Masterclass", "author": "John Doe", "price": 29.99, "in_stock": True},
{"id": 2, "title": "Python for Beginners", "author": "Jane Smith", "price": 19.99, "in_stock": True},
{"id": 3, "title": "Advanced Database Design", "author": "Sam Wilson", "price": 49.99, "in_stock": False},
]

@app.get(
"/books/",
response_model=List[Book],
summary="Get all books",
description="Retrieve the complete list of books in the inventory."
)
async def get_books(
in_stock: Optional[bool] = Query(None, description="Filter by availability")
):
"""
Get all books in the catalog.

You can filter the results by availability using the `in_stock` query parameter.

Examples:
- `/books?in_stock=true` - Returns only books that are in stock
- `/books?in_stock=false` - Returns only books that are out of stock
- `/books` - Returns all books regardless of stock status
"""
if in_stock is not None:
return [book for book in books_db if book["in_stock"] == in_stock]
return books_db

@app.get(
"/books/{book_id}",
response_model=Book,
summary="Get a specific book",
description="Retrieve detailed information about a specific book using its ID."
)
async def get_book(book_id: int):
"""
Get a single book by its ID.

If the book is not found, a 404 error will be returned.
"""
for book in books_db:
if book["id"] == book_id:
return book
raise HTTPException(status_code=404, detail="Book not found")

When you run this application and visit the /docs endpoint, you'll see a well-documented API with descriptions at both the API level and for each endpoint.

Summary

Adding descriptions to your FastAPI endpoints is a simple yet powerful way to improve your API documentation. You've learned several approaches:

  1. Using the description parameter in path operation decorators
  2. Using Python docstrings to document your endpoint functions
  3. Writing multi-line descriptions for complex endpoints
  4. Leveraging Markdown for rich formatting
  5. Combining descriptions with response models for complete documentation

By implementing descriptive documentation in your FastAPI applications, you make your API more accessible to users and easier to maintain for developers.

Further Resources

Exercises

  1. Add proper descriptions to an existing FastAPI application you've built
  2. Create a new endpoint with a description that includes formatting with Markdown
  3. Document a complex endpoint that requires multiple parameters and has several possible responses
  4. Update your function docstrings to make them work well with FastAPI's automatic documentation


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)