pattern-reviewer-fastapi
Skill0 starsChanged 5 months agoMITView on GitHub
FastAPI best-practice audit — router-mount prefix discipline, `Depends()` injection (no inline auth in handlers), Pydantic at boundary only (not deep in domain), app-level exception handlers (every project exception class registered), middleware registration order (`RequestIdMiddleware` last so it runs first), named path constants shared by route + tests, `Settings()` instantiation footgun in `create_app()`, `dependency_overrides` in tests (not `monkeypatch`), per-test app factory.
In this repository74 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- create-bug-issueSkill
- create-enhancement-issueSkill
- create-feature-issuesSkill
- dream-summary-memorySkill
- memory-conventionSkill
- operation-gitSkill
- pattern-architect-api-endpointSkill
- pattern-architect-data-modelSkill
- pattern-architect-deep-moduleSkill
- pattern-e2e-coding-standardSkill
- pattern-engineer-apiSkill
- pattern-engineer-backend-standardSkill
- pattern-engineer-coding-standardSkill
- pattern-engineer-containerSkill
- pattern-engineer-databaseSkill
- pattern-engineer-fastapiSkill
- pattern-engineer-frontend-standardSkill
- pattern-engineer-goSkill
- pattern-engineer-javaSkill
- pattern-engineer-kotlinSkill
- pattern-engineer-nodeSkill
- pattern-engineer-non-functionalSkill
- pattern-engineer-observabilitySkill
- pattern-engineer-pythonSkill
- pattern-engineer-rustSkill
- pattern-engineer-securitySkill
- pattern-engineer-ssrSkill
- pattern-engineer-swiftSkill
- pattern-engineer-typescriptSkill
- pattern-engineer-viteSkill
- pattern-exploratory-testingSkill
- pattern-reviewer-apiSkill
- pattern-reviewer-backend-standardSkill
- pattern-reviewer-coding-standardSkill
- pattern-reviewer-containerSkill
- pattern-reviewer-contractSkill
- pattern-reviewer-databaseSkill
- pattern-reviewer-frontend-standardSkill
- pattern-reviewer-goSkill
- pattern-reviewer-javaSkill
- pattern-reviewer-kotlinSkill
- pattern-reviewer-nodeSkill
- pattern-reviewer-non-functionalSkill
- pattern-reviewer-observabilitySkill
- pattern-reviewer-pythonSkill
- pattern-reviewer-rustSkill
- pattern-reviewer-securitySkill
- pattern-reviewer-ssrSkill
- pattern-reviewer-swiftSkill
- pattern-reviewer-test-coverageSkill
- pattern-reviewer-typescriptSkill
- pattern-reviewer-viteSkill
- pattern-test-coverageSkill
- principle-engineer-tddSkill
- scaffold-projectSkill
- workflow-architect-interviewSkill
- workflow-designer-sample-pagesSkill
- workflow-design-interviewSkill
- workflow-e2e-authorSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 17
After loading this skill, also check $MAIN_ROOT/.claude/memory/patterns/pattern-reviewer-fastapi.md in the consuming project (resolve …
- Very specific: line 36
Every external dep enters via Depends() — DB session, settings, current-user resolver, rate limiter, idempotency-key extractor.
- Very specific: line 121
Every 4xx / 5xx body must carry a non-null request_id — pin with a test that walks app.user_middleware and asserts the request-id …
- Very specific: line 147
Use the shape in templates/review-comment.md.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
pattern-reviewer-fastapi
FastAPI implementation best-practice audit. This skill focuses on FastAPI-specific mechanics — contract-conformance checks (path / verb / status code / response shape / error envelope shape / idempotency policy / rate-limit policy) are out of scope here.
When to activate
- Reviewing a diff that includes FastAPI routes, dependencies, middleware, exception handlers, or
create_app()/main.py. - A user says "review the FastAPI wiring / dependencies / middleware order".
Project memory overlay
After loading this skill, also check $MAIN_ROOT/.claude/memory/patterns/pattern-reviewer-fastapi.md in the consuming project (resolve MAIN_ROOT="$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")"). If present, load it as an additive overlay to the rules below; if absent, skip silently. See memory-convention for the full contract (additivity, severity floor, conflict surfacing).
Iron rules
- >80% confidence filter. Report only when you are >80% confident. Consolidate similar findings.
- Cite
path/to/file.ext:line. Quote the offending snippet in a BAD block; show the fix in a GOOD block. - Severity is load-bearing. CRITICAL / HIGH block the gate; MEDIUM / LOW are informational. Use the per-pattern severity assigned below.
- Never refer to a finding as
#N— GitHub auto-links those to issues. Use a non-numeric handle (quoted title,F1/F2,Finding 1).
Patterns to review
Router mounting (MEDIUM)
- Each
APIRoutermounts with an explicit prefix:app.include_router(users_router, prefix="/api/v1/users", tags=["users"]). This rule is "prefix explicit, not implicit" — contract-prefix conformance is out of scope here. - Routes from multiple resources collapsed into a single "kitchen-sink" router → flag.
- Missing
tags=→ LOW (OpenAPI groups won't render right).
Depends() discipline (HIGH)
- Every external dep enters via
Depends()— DB session, settings, current-user resolver, rate limiter, idempotency-key extractor. - Auth guards inline in the handler body → flag; move to
Depends(require_admin)orDepends(get_current_user). Dependschains deeper than 2–3 levels → MEDIUM (the seam belongs in a service module).
# BAD — inline auth
@router.post("/admin/users/{user_id}")
def delete_user(user_id: int, request: Request, db: Session = Depends(get_db)):
token = request.headers.get("Authorization")
user = decode_jwt(token)
if user.role != "admin": raise HTTPException(403)
db.execute("DELETE FROM users WHERE id = :id", {"id": user_id})
# GOOD — Depends-based guard
@router.post("/admin/users/{user_id}", dependencies=[Depends(require_admin)])
def delete_user(user_id: int, db: Session = Depends(get_db)):
db.execute("DELETE FROM users WHERE id = :id", {"id": user_id})Settings() footgun in create_app() (HIGH)
# BAD — crashes any test fixture that builds the app without a full env
def create_app() -> FastAPI:
settings = Settings() # ValidationError if DATABASE_URL / APP_ORIGIN missing
app = FastAPI()
app.add_middleware(SessionMiddleware, https_only=settings.secure_cookies)
return app
# GOOD — cookie knob readable independently of Settings
def _secure_cookies() -> bool:
return os.getenv("SECURE_COOKIES", "true").lower() != "false"
def create_app(*, settings: Settings | None = None) -> FastAPI:
app = FastAPI()
app.add_middleware(SessionMiddleware, https_only=_secure_cookies())
return appSettings()instantiated unconditionally increate_app()purely to read one boolean → flag.
Pydantic at boundary only (MEDIUM)
- Pydantic models on request bodies, response models, query params — yes.
- Pydantic models passed deep into the domain layer / DB / business logic → flag; convert to dataclass at the seam.
Request vs response model separation (MEDIUM)
# BAD — same model used for both directions
class User(BaseModel):
id: int | None = None # only set on response
email: str
password: str # only set on request — and now in OpenAPI response schema
@router.post("", response_model=User)
def create_user(body: User) -> User: ...
# GOOD — distinct shapes
class UserCreate(BaseModel):
email: str
password: str
class UserRead(BaseModel):
id: int
email: str
@router.post("", response_model=UserRead)
def create_user(body: UserCreate) -> UserRead: ...A single Pydantic model used as BOTH the route's request body and its response_model → MEDIUM. Write-side fields (passwords, raw tokens, internal write toggles) leak into the OpenAPI response schema; response-side fields (server-issued ids, derived values) silently become optional on the request side.
Exception handlers register at app level (HIGH)
- App-level handlers register for project exceptions:
@app.exception_handler(LoginError). - Inline
HTTPException(status_code=..., detail=...)for a project-wide error class → flag (move to a handler). - Generic 500 handler exists; logs the full exception server-side.
(This rule is "handler exists at app level, not inline" — error-envelope-shape conformance is out of scope here.)
Middleware registration order (HIGH)
app.add_middleware(...)runs in reverse order on the response.RequestIdMiddlewareis the lastadd_middlewarecall so it runs first on rejection paths.- Every 4xx / 5xx body must carry a non-null
request_id— pin with a test that walksapp.user_middlewareand asserts the request-id middleware is at the top.
Path constants (MEDIUM)
- Paths used in BOTH the route decorator AND tests must be defined once as a module-level constant.
@router.post("/api/v1/users")+client.post("/api/v1/users")in a test → flag; both should importUSERS_PATH.
(This rule is "constant exists; route + tests share it" — whether the constant's value matches the api contract is out of scope here.)
Lifespan + background tasks (MEDIUM)
- Startup / shutdown hooks in
lifespancontext manager, not deprecated@app.on_event. BackgroundTasksparameter only for fire-and-forget work that can lose to a crash; persistent work uses a real queue.
dependency_overrides in tests (MEDIUM)
- Tests override deps via
app.dependency_overrides[real_dep] = fake_dep. monkeypatch/unittest.mock.patchon the module-level dep function → flag; usedependency_overrides.
Test app factory (MEDIUM)
- Tests build the app per-test via
create_app(settings=fake_settings); never share a singleton across tests. - Module-level
app = create_app()imported by tests → flag; that shape leaks state across tests.
Constructing the finding
Use the shape in templates/review-comment.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

