FastAPI Routes
context7: If the
context7_query-docstool is available, resolve and load the fullfastapidocumentation before proceeding:context7_resolve-library-id: "fastapi" context7_query-docs: /fastapi/fastapi "<your query>"
Guidelines and patterns for writing FastAPI routes in this codebase.
REST Principles
APIs must adhere as closely as possible to REST principles, including appropriate use of HTTP verbs:
| Verb | Usage |
|---|---|
GET |
Read one or many resources |
POST |
Create a new resource |
PUT |
Replace / fully update a resource |
PATCH |
Partial update (use sparingly) |
DELETE |
Remove a resource |
Pydantic Models
- Always use Pydantic models for both input and output — never use plain
dictorAny. - Never reuse the same model for input and output. Use separate models:
PostCreate— user input for creating a resourcePostUpdate— user input for updating (optional fields)PostRead— response shape returned to the client
- Parameters in input models must use
Field()with validation constraints and adescription. - Output models do not require
Field()unless you need aliases or serialization control.
from uuid import UUID
from pydantic import BaseModel, Field
class PostCreate(BaseModel):
title: str = Field(min_length=1, max_length=200, description="Post title")
content: str = Field(min_length=1, description="Post content")
class PostRead(BaseModel):
id: UUID
title: str
content: str
created_at: str
class PostUpdate(BaseModel):
title: str | None = Field(default=None, max_length=200, description="Post title")
content: str | None = Field(default=None, description="Post content")
Router Pattern
Use APIRouter for all routes. Register the router in {{cookiecutter.__package_slug}}/www.py.
from uuid import UUID
from fastapi import APIRouter, status
router = APIRouter()
@router.post("/posts", response_model=PostRead, status_code=status.HTTP_201_CREATED)
async def create_post(post: PostCreate) -> PostRead:
...
@router.get("/posts/{post_id}", response_model=PostRead)
async def get_post(post_id: UUID) -> PostRead:
...
@router.put("/posts/{post_id}", response_model=PostRead)
async def update_post(post_id: UUID, post: PostUpdate) -> PostRead:
...
@router.delete("/posts/{post_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_post(post_id: UUID) -> None:
...
Route Registration
Register routers in {{cookiecutter.__package_slug}}/www.py using app.include_router().
Exceptions (no prefix by convention):
/health— liveness probe/— root redirect to docs/static— static file serving
OpenAPI Docs
The OpenAPI documentation is served at these fixed paths — do not move them:
| URL | Interface |
|---|---|
/docs |
Swagger UI |
/redoc |
ReDoc |
/openapi.json |
Raw schema |
Error Handling
Use HTTPException with appropriate status codes:
from fastapi import HTTPException, status
@router.get("/posts/{post_id}", response_model=PostRead)
async def get_post(post_id: UUID) -> PostRead:
post = await get_post_from_db(post_id)
if post is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Post not found")
return post
Dependency Injection
Use Depends() to inject shared logic (database sessions, authentication, etc.) into routes.
from fastapi import Depends
from {{cookiecutter.__package_slug}} import get_db
@router.get("/posts/{post_id}", response_model=PostRead)
async def get_post(post_id: UUID, db = Depends(get_db)) -> PostRead:
...
Lifespan
Use the lifespan parameter on the FastAPI app instance for startup and shutdown logic. Do not use the deprecated @app.on_event("startup") / @app.on_event("shutdown") decorators.
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup logic
await initialize_database()
yield
# Shutdown logic
await close_database()
app = FastAPI(lifespan=lifespan)
Style Checklist
Before submitting a new route, verify:
- HTTP verb matches the operation semantics
- Separate
Create,Update, andReadmodels defined - All input model fields use
Field()with description - Route is
async - Router is registered in
{{cookiecutter.__package_slug}}/www.py - 201 status used for
POSTcreate endpoints - 204 status used for
DELETEendpoints (no response body) - Path parameters use typed UUIDs where appropriate
Further Reading
- docs/dev/api.md — Full FastAPI developer guide covering the application structure, startup events, Swagger UI, ReDoc, OpenAPI schema, middleware, and dependency injection patterns.
- FastAPI Docs
Source: tedivm/robs_awesome_python_template — distributed by TomeVault.