| name | fastapi-routes |
| description | Create or modify FastAPI routes in the Oscilla codebase. Use when: adding new API endpoints, creating Pydantic request/response models, registering routers, designing REST APIs, or following route conventions for this project. |
FastAPI Routes
context7: If the mcp_context7 tool is available, resolve and load the full fastapi documentation before proceeding:
mcp_context7_resolve-library-id: "fastapi"
mcp_context7_get-library-docs: <resolved-id>
Guidelines and patterns for writing FastAPI routes in the Oscilla 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
dict or Any.
- Never reuse the same model for input and output. Use separate models:
PostCreate — user input for creating a resource
PostUpdate — user input for updating (optional fields)
PostRead — response shape returned to the client
- Parameters in input models must use
Field() with validation constraints and a description.
- 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)
content: str | None = None
Router Pattern
Use APIRouter for all routes. Register the router in oscilla/www.py under the /api prefix.
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
All application routes must be registered under the /api prefix in oscilla/www.py.
Exceptions (no /api prefix by convention):
/health — liveness probe
/ready — readiness probe
/static — static file serving
app.include_router(posts_router, prefix="/api")
OpenAPI Docs
The OpenAPI documentation is served at these fixed paths — do not move them:
| URL | Interface |
|---|
/api/docs | Swagger UI |
/api/redoc | ReDoc |
/api/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
Style Checklist
Before submitting a new route, verify:
Further Reading
- docs/dev/api.md — Full FastAPI developer guide covering the application structure, startup events, Swagger UI (
/api/docs), ReDoc (/api/redoc), OpenAPI schema, middleware, authentication integration, and dependency injection patterns.
- docs/dev/authentication.md — Authentication and authorization patterns used in this project.
- docs/dev/dependencies.md — FastAPI dependency injection conventions.
- FastAPI Docs