FastAPI Reference
FastAPI Reference for domus-api
This reference maps FastAPI concepts directly to patterns used in domus-api. Every example is drawn from the actual codebase.
Learning Path
The FastAPI tutorial at fastapi.tiangolo.com/tutorial/ covers 40 topics. For domus-api, the critical ones are:
| Priority | Topic | Why It Matters for domus-api |
|---|---|---|
P0 |
This IS domus-api’s structure: APIRouter per domain, include_router in main.py |
|
P0 |
Every |
|
P0 |
Filtering: |
|
P0 |
Every POST endpoint: |
|
P0 |
|
|
P1 |
Replace the current |
|
P1 |
|
|
P1 |
Custom |
|
P2 |
CORS is already configured. Add request logging, timing middleware. |
|
P2 |
Cache refresh, git commit after write operations |
|
P2 |
Customize the Swagger UI title, description, tags |
|
P3 |
API key auth when exposing beyond localhost |
How domus-api Maps to FastAPI Patterns
APIRouter (Bigger Applications)
domus-api uses one router per content domain — this is the official FastAPI pattern for large apps:
# routes/codex.py — one domain, one router
from fastapi import APIRouter
router = APIRouter(prefix="/codex", tags=["codex"])
@router.get("")
async def list_codex_categories():
...
@router.get("/{category}")
async def list_codex_entries(category: str):
...
# main.py — register all routers
from domus_api.routes import codex, patterns, search, ...
app.include_router(codex.router)
app.include_router(patterns.router)
app.include_router(search.router)
# ... 25 routers total
Path Parameters
Three patterns used in domus-api:
# Simple parameter
@router.get("/{category}")
async def list_entries(category: str): # "bash", "vim", "git"
...
# Path with slashes (file paths)
@router.get("/{path:path}")
async def get_page(path: str): # "standards/operations/change-control"
...
# Enum for controlled vocabulary
class Severity(str, Enum):
P1 = "P1"
P2 = "P2"
P3 = "P3"
P4 = "P4"
Query Parameters
from fastapi import Query
@router.get("/pages")
async def list_pages(
category: str | None = Query(None, description="Filter by category"),
limit: int = Query(100, ge=1, le=500),
offset: int = Query(0, ge=0),
):
...
@router.get("/search")
async def search(
q: str = Query(..., min_length=2), # ... means required
scope: str | None = Query(None),
):
...
Request Body (Pydantic Models)
from pydantic import BaseModel, Field
class IncidentCreate(BaseModel):
severity: Severity
description: str = Field(min_length=5, max_length=200)
systems_affected: str | None = None
@router.post("/case-studies/incidents", status_code=201)
async def create_incident(incident: IncidentCreate):
# FastAPI auto-validates, auto-documents, auto-rejects bad input
result = scaffolder.create_incident(
severity=incident.severity.value,
description=incident.description,
)
return result
Response Models
class PageSummary(BaseModel):
path: str
title: str | None = None
category: str
attributes: dict[str, str] = {}
class PageList(BaseModel):
total: int
pages: list[PageSummary]
@router.get("", response_model=PageList)
async def list_pages(...):
# FastAPI validates the response matches PageList
...
Dependency Injection (Next Improvement)
The current cache injection pattern:
# CURRENT (works but not idiomatic)
cache: DocumentCache = None # type: ignore
# Injected in lifespan: codex.cache = doc_cache
The proper FastAPI way with Depends():
# BETTER — dependency injection
from fastapi import Depends
def get_cache() -> DocumentCache:
return doc_cache # module-level singleton
@router.get("")
async def list_codex(cache: DocumentCache = Depends(get_cache)):
...
Testing (Next Improvement)
# tests/test_pages.py
from fastapi.testclient import TestClient
from domus_api.main import app
client = TestClient(app)
def test_health():
r = client.get("/")
assert r.status_code == 200
assert r.json()["status"] == "operational"
def test_search():
r = client.get("/search?q=mandiant")
assert r.status_code == 200
assert r.json()["total"] > 0
def test_create_incident():
r = client.post("/case-studies/incidents", json={
"severity": "P4",
"description": "Test incident from pytest"
})
assert r.status_code == 201
assert "INC-" in r.json()["id"]
Key Concepts
| Concept | domus-api Usage |
|---|---|
|
All route handlers are async. FastAPI runs them on the event loop. |
Type hints |
Every parameter and return type is annotated. FastAPI uses these for validation, docs, and serialization. |
Pydantic BaseModel |
Request bodies ( |
|
Controlled vocabularies: |
|
POST endpoints return 201 Created, not 200 OK. |
|
Tells FastAPI to validate and filter the response. Strips extra fields. |
|
Groups endpoints in Swagger UI. One tag per router. |
Lifespan |
|
CORS Middleware |
|
OpenAPI auto-generation |
|
Further Reading
-
FastAPI Tutorial — the complete 40-topic guide
-
Advanced User Guide — middleware, events, custom responses
-
Pydantic v2 Docs — model validation, serialization
-
HTTPX Docs — the HTTP client used for testing
-
Uvicorn Docs — ASGI server configuration