FastAPI Tag Organization
Introduction
As your FastAPI application grows in size and complexity, organizing your endpoints becomes increasingly important. Tags in FastAPI provide a powerful way to logically group your API endpoints, making your documentation more organized and your API easier to navigate. This organization is especially valuable for other developers who will interact with your API through the automatically generated Swagger UI or ReDoc interfaces.
In this guide, we'll explore how to effectively use tags in FastAPI to organize your API endpoints, improve your documentation, and make your API more maintainable.
Understanding Tags in FastAPI
Tags in FastAPI are simple string identifiers that you can attach to your API route operations (endpoints). They serve two main purposes:
- Documentation Organization: Tags group related endpoints in the automatically generated API documentation.
- Code Organization: Tags help you logically group related functionality in your codebase.
Basic Tag Usage
Let's start with a simple example of how to apply tags to your FastAPI endpoints:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/", tags=["users"])
async def get_users():
return [{"name": "John"}, {"name": "Jane"}]
@app.post("/users/", tags=["users"])
async def create_user(name: str):
return {"message": f"User {name} created"}
@app.get("/items/", tags=["items"])
async def get_items():
return [{"name": "Laptop"}, {"name": "Smartphone"}]
@app.post("/items/", tags=["items"])
async def create_item(name: str):
return {"message": f"Item {name} created"}
In this example, we've organized our endpoints into two tags: "users" and "items". When you access the Swagger UI (at /docs
), these endpoints will be grouped under their respective tag sections.
Multiple Tags for an Endpoint
You can apply multiple tags to a single endpoint if it relates to multiple categories:
@app.get("/user-items/{user_id}", tags=["users", "items"])
async def get_user_items(user_id: int):
return {"user_id": user_id, "items": [{"name": "Laptop"}, {"name": "Smartphone"}]}
This endpoint will appear in both the "users" and "items" sections of your API documentation.
Tag Ordering and Customization
FastAPI allows you to customize how tags are displayed in your documentation by defining them in your FastAPI application:
from fastapi import FastAPI
app = FastAPI(
title="My Super API",
description="This is a very fancy API",
version="1.0.0",
openapi_tags=[
{
"name": "users",
"description": "Operations related to users",
},
{
"name": "items",
"description": "Operations related to items",
"externalDocs": {
"description": "Items external docs",
"url": "https://example.com/items/",
},
},
]
)
# Your endpoints here...
The openapi_tags
parameter lets you:
- Define the order in which tags appear in your documentation
- Add descriptions to your tags
- Link to external documentation
Organizing Routes with Tags and APIRouter
For larger applications, you can combine tags with FastAPI's APIRouter
to organize your code more effectively:
from fastapi import FastAPI, APIRouter
app = FastAPI()
# Create routers with predefined tags
user_router = APIRouter(prefix="/users", tags=["users"])
item_router = APIRouter(prefix="/items", tags=["items"])
# Add routes to the user router
@user_router.get("/")
async def get_users():
return [{"name": "John"}, {"name": "Jane"}]
@user_router.post("/")
async def create_user(name: str):
return {"message": f"User {name} created"}
# Add routes to the item router
@item_router.get("/")
async def get_items():
return [{"name": "Laptop"}, {"name": "Smartphone"}]
@item_router.post("/")
async def create_item(name: str):
return {"message": f"Item {name} created"}
# Include the routers in the main app
app.include_router(user_router)
app.include_router(item_router)
This approach has several advantages:
- You can organize related routes in separate files
- Every route in a router automatically gets the same prefix and tags
- Code is more modular and maintainable
Real-World Example: E-commerce API
Let's look at a more comprehensive example for an e-commerce API with multiple tags:
from fastapi import FastAPI, APIRouter, Depends, HTTPException
from pydantic import BaseModel
from typing import List, Optional
app = FastAPI(
title="E-commerce API",
description="API for managing an e-commerce platform",
version="1.0.0",
openapi_tags=[
{"name": "users", "description": "Operations related to users and authentication"},
{"name": "products", "description": "Product catalog management"},
{"name": "orders", "description": "Order processing and history"},
{"name": "cart", "description": "Shopping cart operations"},
{"name": "admin", "description": "Administrative operations"}
]
)
# Models
class User(BaseModel):
id: Optional[int] = None
username: str
email: str
class Product(BaseModel):
id: Optional[int] = None
name: str
price: float
description: str
# User routes
@app.post("/users/", tags=["users"])
async def create_user(user: User):
return {"id": 1, **user.dict()}
@app.get("/users/{user_id}", tags=["users"])
async def get_user(user_id: int):
return {"id": user_id, "username": "johndoe", "email": "[email protected]"}
# Product routes
@app.get("/products/", tags=["products"])
async def list_products():
return [
{"id": 1, "name": "Laptop", "price": 999.99},
{"id": 2, "name": "Smartphone", "price": 499.99}
]
@app.get("/products/{product_id}", tags=["products"])
async def get_product(product_id: int):
return {"id": product_id, "name": "Laptop", "price": 999.99}
@app.post("/products/", tags=["products", "admin"])
async def create_product(product: Product):
return {"id": 3, **product.dict()}
# Order routes
@app.get("/orders/", tags=["orders"])
async def list_orders():
return [
{"id": 1, "user_id": 1, "products": [1, 2], "total": 1499.98},
{"id": 2, "user_id": 2, "products": [1], "total": 999.99}
]
@app.post("/orders/", tags=["orders", "cart"])
async def create_order():
return {"message": "Order created", "order_id": 3}
# Cart routes
@app.get("/cart/", tags=["cart"])
async def get_cart():
return {"items": [{"product_id": 1, "quantity": 2}]}
@app.post("/cart/add", tags=["cart"])
async def add_to_cart(product_id: int, quantity: int = 1):
return {"message": f"Added {quantity} of product {product_id} to cart"}
# Admin routes
@app.get("/admin/stats", tags=["admin"])
async def admin_stats():
return {"users": 100, "products": 50, "orders": 200, "revenue": 15000}
When you view this API in Swagger UI, you'll see the endpoints neatly organized under their respective tags, making it much easier to navigate and understand the API's capabilities.
Tag Best Practices
Here are some best practices when using tags in your FastAPI applications:
-
Use Consistent Naming: Decide on a naming convention for your tags and stick to it.
-
Group by Resource or Function: Tags typically represent either resources (users, products) or functional areas (authentication, admin).
-
Don't Over-Tag: Too many tags can be as confusing as no tags. Aim for a reasonable number.
-
Use APIRouter for Large Applications: For larger apps, combine tags with APIRouter to organize your code into modules.
-
Document Your Tags: Always provide descriptions for your tags in the
openapi_tags
parameter. -
Consider Tag Hierarchy: If you have many endpoints, consider creating a tag hierarchy (e.g., "products", "products-inventory", "products-pricing").
-
Separate Public and Admin APIs: Use different tags for public-facing endpoints versus administrative endpoints.
Summary
FastAPI tags provide a simple but powerful way to organize your API endpoints, both in the code and in the automatically generated documentation. By using tags strategically, you can:
- Create a more intuitive API structure
- Improve the developer experience for API consumers
- Make your code more maintainable
- Separate concerns by functionality or resource type
Whether you're building a small API or a large enterprise system, proper tag organization can significantly improve the clarity and maintainability of your FastAPI application.
Additional Resources
- FastAPI Official Documentation on Tags
- OpenAPI Specification (the standard that powers FastAPI's documentation)
- API Design Best Practices
Exercises
- Refactor an existing FastAPI application to use appropriate tags.
- Create a new FastAPI application for a blog with at least five different tags.
- Implement tag descriptions and external documentation links for an API.
- Combine APIRouter and tags to create a modular API with different files for each resource type.
- Create a hierarchical tag structure for a complex application domain.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)