fastapi-standards
Skill1 starsChanged 5 months agoMITView on GitHub
Best-practice coding standards for FastAPI services (FastAPI app, APIRouter, Pydantic v2). OVERLAY — load python-standards FIRST, then apply these. Covers project structure, async, dependency injection, Pydantic models, JWT auth, URI versioning, SQLAlchemy/Alembic, testing. Used by the review agents on FastAPI code. Do NOT use for non-Python web frameworks.
In this repository19 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- custom-standardsSkill
- agent-code-to-confirmSkill
- agent-to-confirmSkill
- claude-guideline-creationSkill
- skill-creatorSkill
- youtube-to-guidelineSkill
- youtube-transcribeSkill
- general-standardsSkill
- go-standardsSkill
- java-standardsSkill
- nextjs-standardsSkill
- nodejs-standardsSkill
- python-standardsSkill
- react-standardsSkill
- reviewing-codebasesSkill
- rust-standardsSkill
- skill-toggleSkill
- typescript-standardsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. About 0 are common, 3 are distinctive, and 11 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 78
FASTAPI-STRUCT-4 (SHOULD NOT): Put blocking work, DB calls, or business logic directly in a path operation function — delegate to the …
- Very specific: line 90
FASTAPI-MODEL-1 (MUST): Every request body is a Pydantic BaseModel (not a raw dict).
- Very specific: line 97
FASTAPI-MODEL-3 (MUST): Use separate input and output schemas (e.g.
- Distinctive: line 98
Never accept or echo server-controlled fields (id, timestamps, roles) through the input model.
- Very specific: line 102
FASTAPI-MODEL-5 (SHOULD): Use Pydantic v2 idioms — @field_validator/@model_validator, model_dump()/model_validate(), model_config.
- Very specific: line 124
FASTAPI-DEP-1 (MUST): Use Depends for shared cross-cutting concerns — DB sessions, the current authenticated user, pagination, settings.
- Very specific: line 127
FASTAPI-DEP-2 (SHOULD): Use the Annotated[T, Depends(...)] style (optionally a shared type alias) rather than the legacy default-value = …
- Very specific: line 138
FASTAPI-ASYNC-1 (MUST): Use async def for path operations and dependencies that perform I/O with async libraries.
- Distinctive: line 141
FASTAPI-ASYNC-2 (MUST): If an operation must call blocking code, either define it as a plain
- Very specific: line 144
FASTAPI-ASYNC-3 (SHOULD): Use an async HTTP client (httpx.AsyncClient) for outbound calls, constructed once (lifespan/dependency) and …
- Very specific: line 156
FASTAPI-ERR-3 (MUST): Do not leak internals — unhandled exceptions return a generic 500 with no traceback/secret to the client (fulfils …
- Very specific: line 158
FASTAPI-ERR-4 (SHOULD): Use accurate, semantic status codes via the status module (status.HTTP_404_NOT_FOUND), and set status_code= on …
- Very specific: line 178
FASTAPI-SEC-5 (SHOULD): Don't expose interactive docs (/docs, /redoc) or the OpenAPI schema on untrusted/production surfaces without …
- Very specific: line 204
FASTAPI-TEST-1 (MUST): Test endpoints with FastAPI's TestClient (or httpx.AsyncClient + ASGITransport) at the app boundary, covering …
≈ “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
FastAPI Coding Standard (v1.0 — LOCKED)
Status: ✅ Locked — all review questions resolved (decision log at end). An overlay that builds on the locked Python core (
codebase-standards/python.mdv1.0) the way Next.js builds on React. A FastAPI service is first a Python service — everyPY-*rule applies (3.12 floor, mypy --strict, uv, Ruff, Google docstrings, ≥80% changed-code coverage). This document adds only the web-framework specifics (FASTAPI-*rules). Same constraint language, rule-ID format, and severity mapping as the template.On adoption this becomes
.claude/skills/fastapi-standards/SKILL.md+references/*.md.
Toolchain verified current as of 2026-06-13 (via Context7 + PyPI): FastAPI 0.136.x, Pydantic v2 (2.13.x), Starlette 1.3.x, Uvicorn 0.49.x,
pydantic-settings2.14.x,httpx0.28.x. Rules are written version-agnostically; these are reference points, not pins.
How to read this document
Constraint language (RFC 2119)
- MUST / MUST NOT — hard requirement; a violation is a blocking issue.
- SHOULD / SHOULD NOT — strong recommendation; deviate only with a written
# Justification:. - MAY — optional.
Rule IDs
Stable FASTAPI-AREA-NUMBER (e.g. FASTAPI-ERR-2). The reviewer MUST cite the rule ID. Never
renumber; add new numbers. PY-* IDs from the Python core still apply and are cited as-is.
Severity mapping
| This document says… | Reviewer severity | Gate |
MUST/MUST NOT in Security | Critical | Blocks merge |
MUST/MUST NOT elsewhere | Critical / Warning (by impact) | Blocks if it risks correctness/data loss |
SHOULD without justification | Warning | Should fix |
MAY / stylistic | Suggestion | Nice to have |
Scope & Assumptions
- Target: HTTP APIs and services built on FastAPI (Pydantic v2, served by Uvicorn).
- Inherits the Python core in full — this overlay never relaxes a
PY-*rule, only adds to it. - Pydantic v2 is assumed. v1-only syntax (
@validator,.dict(),Configclass) is treated as legacy; use v2 (@field_validator,.model_dump(),model_config). - Custom overrides: the project's
custom-standardsskill overrides this document on conflict.
How this overlay extends the Python core
Python core rule FastAPI mechanism that fulfills/strengthens it PY-SEC-1(validate all inbound)Pydantic request models + Query()/Path()constraints +extra="forbid"PY-ERR-3/5(typed errors, no leaks)HTTPException+ registered exception handlers with a stable error shapePY-CONF-1/2(single validated config)pydantic-settingsBaseSettings, validated at startupPY-STRUCT-2(layering)APIRouter(transport) → service functions (logic) → repository (data)PY-SEC-5(password hashing)FastAPI security deps + Argon2/bcrypt/pwdlib (per PY-SEC-5)
1. Application & Project Structure
- FASTAPI-STRUCT-1 (MUST): Split routes into
APIRoutermodules by feature andinclude_routerthem on the app — do not define all endpoints on a singleFastAPI()instance. Keep the layering ofPY-STRUCT-2: routers handle transport only (parse request, call a service, shape response); business logic lives in service functions; data access is isolated. - FASTAPI-STRUCT-2 (SHOULD): Build the app in an app factory (
create_app() -> FastAPI) so it can be constructed with test/overridden config. Register routers, middleware, and exception handlers there. - FASTAPI-STRUCT-3 (MUST): Manage startup/shutdown with the
lifespanasync context manager (not the deprecated@app.on_event). Open pools/clients on startup and close them on shutdown — this is howPY-level graceful shutdown is realized for the service. - FASTAPI-STRUCT-4 (SHOULD NOT): Put blocking work, DB calls, or business logic directly in a path operation function — delegate to the service layer.
- FASTAPI-STRUCT-5 (SHOULD): Access relational data through a mature ORM with versioned
migrations, kept behind the repository/data layer (never raw SQL strings in handlers — see
PY-SEC-2). Recommended default: SQLAlchemy 2.0 (async) + Alembic migrations (or SQLModel, the FastAPI-author's SQLAlchemy+Pydantic layer). The ORM library is recommended, not mandated — but migrations and the data-layer boundary are required.
2. Request & Response Models
- FASTAPI-MODEL-1 (MUST): Every request body is a Pydantic
BaseModel(not a rawdict). Path/query/header params use typed parameters with validation (Annotated[int, Path(gt=0)],Annotated[str, Query(max_length=50)]). - FASTAPI-MODEL-2 (MUST): Declare an explicit
response_model(or a typed return annotation) on operations that return data. FastAPI filters the response to that schema — this is the enforcement point forPY-level "never serialize secrets": MUST NOT return ORM/DB objects directly; map to a response schema that omits sensitive fields. - FASTAPI-MODEL-3 (MUST): Use separate input and output schemas (e.g.
UserCreatevsUserRead). Never accept or echo server-controlled fields (id, timestamps, roles) through the input model. - FASTAPI-MODEL-4 (SHOULD): Reject unknown fields on request models with
model_config = {"extra": "forbid"}(mirrorsPY-SEC-1). Add field constraints withField(..., gt=, max_length=, pattern=)rather than hand-rolled checks. - FASTAPI-MODEL-5 (SHOULD): Use Pydantic v2 idioms —
@field_validator/@model_validator,model_dump()/model_validate(),model_config. Flag v1@validator,.dict(), innerConfig.
class UserCreate(BaseModel):
model_config = {"extra": "forbid"} # FASTAPI-MODEL-4
email: EmailStr
password: str = Field(min_length=12)
class UserRead(BaseModel): # FASTAPI-MODEL-3: no password field
id: int
email: EmailStr
@router.post("/users", response_model=UserRead, status_code=status.HTTP_201_CREATED)
async def create_user(payload: UserCreate, svc: Annotated[UserService, Depends(get_user_service)]):
return await svc.create(payload) # returns a UserRead-shaped object, never the ORM row3. Dependency Injection
- FASTAPI-DEP-1 (MUST): Use
Dependsfor shared cross-cutting concerns — DB sessions, the current authenticated user, pagination, settings. MUST NOT reach for module-level globals or construct these inline in each handler. - FASTAPI-DEP-2 (SHOULD): Use the
Annotated[T, Depends(...)]style (optionally a shared type alias) rather than the legacy default-value= Depends(...)form. - FASTAPI-DEP-3 (MUST): Acquire and release per-request resources (DB sessions, transactions) via a
dependency with
yield, so cleanup runs even on error. - FASTAPI-DEP-4 (SHOULD): Enforce authentication/authorization through dependencies (route- or
router-level
dependencies=[...]), not ad-hoc checks inside handlers.
4. Async & Concurrency
- FASTAPI-ASYNC-1 (MUST): Use
async deffor path operations and dependencies that perform I/O with async libraries. Inside them, never block the event loop (PY-ASYNC-1) — no sync DB drivers,requests,time.sleep, or CPU-heavy loops. - FASTAPI-ASYNC-2 (MUST): If an operation must call blocking code, either define it as a plain
def(FastAPI runsdefendpoints in a threadpool) or offload viarun_in_threadpool/asyncio.to_thread— do not call blocking code from inside anasync defpath operation. - FASTAPI-ASYNC-3 (SHOULD): Use an async HTTP client (
httpx.AsyncClient) for outbound calls, constructed once (lifespan/dependency) and reused — not a new client per request, and notrequests.
5. Error Handling
- FASTAPI-ERR-1 (MUST): Raise
HTTPException(or a subclass) for expected client-facing errors with the correct status code — don't return{"error": ...}dicts with a 200. - FASTAPI-ERR-2 (MUST): Map domain exceptions to HTTP responses in registered exception handlers
(
@app.exception_handler(...)), not by try/except in every handler. Provide a consistent error response shape across the API. - FASTAPI-ERR-3 (MUST): Do not leak internals — unhandled exceptions return a generic 500 with no
traceback/secret to the client (fulfils
PY-ERR-5); full detail is logged server-side. - FASTAPI-ERR-4 (SHOULD): Use accurate, semantic status codes via the
statusmodule (status.HTTP_404_NOT_FOUND), and setstatus_code=on operations that aren't a plain 200.
6. Security (violations here are Critical / blocking)
- FASTAPI-SEC-1 (MUST): Protect non-public endpoints with auth enforced via dependencies
(route/router
dependencies=[...]). Verify the credential and check authorization (scopes/roles), not just authentication. Default scheme: stateless JWT bearer tokens viaOAuth2PasswordBearer(token in theAuthorization: Bearerheader). Sanctioned alternatives, by context: httpOnly session cookies for browser-first apps (token not exposed to JS), or an external IdP / OAuth2 provider (Keycloak, Auth0, etc.) for larger systems. Whatever the scheme, it MUST be enforced centrally via dependencies, not ad-hoc per handler. - FASTAPI-SEC-2 (MUST): Configure CORS deliberately via
CORSMiddleware— an explicit origin allowlist; MUST NOT combineallow_origins=["*"]withallow_credentials=True. - FASTAPI-SEC-3 (MUST): Apply rate limiting to public/auth/webhook endpoints (e.g.
slowapi, or the API gateway/reverse proxy). Cap request body size. - FASTAPI-SEC-4 (MUST): Hash passwords with Argon2/bcrypt per
PY-SEC-5(argon2-cffi,bcrypt, orpwdlib); store only hashes; usesecrets/cryptofor tokens. Never log credentials or tokens. - FASTAPI-SEC-5 (SHOULD): Don't expose interactive docs (
/docs,/redoc) or the OpenAPI schema on untrusted/production surfaces without protection — disable or gate them as appropriate.
7. Configuration
- FASTAPI-CONF-1 (MUST): Load configuration with
pydantic-settingsBaseSettings, exposed as a cached dependency (@lru_cache get_settings), validated at startup — fulfilsPY-CONF-1/2. Read config through the settings object/dependency, not scatteredos.environaccess.
8. API Design & Documentation
- FASTAPI-DOC-1 (SHOULD): Lean on FastAPI's auto OpenAPI — give operations
tags,summary, and response models so the generated schema is accurate and useful. Keep it in sync by construction. - FASTAPI-DOC-2 (SHOULD): Version the public API with a URI prefix (
/v1) on the router (APIRouter(prefix="/v1")) — URI versioning is the standard. Keep URL/resource naming consistent (plural nouns, no verbs in paths). Header/media-type versioning is an acceptable alternative if a team standardizes on it; internal-only APIs MAY defer versioning until a v2 is actually needed.
9. Testing
- FASTAPI-TEST-1 (MUST): Test endpoints with FastAPI's
TestClient(orhttpx.AsyncClient+ASGITransport) at the app boundary, covering success, validation (422), auth (401/403), and error paths. - FASTAPI-TEST-2 (MUST): Isolate external systems in tests with dependency overrides
(
app.dependency_overrides) — e.g. swap the DB/session or auth dependency — rather than monkey-patching internals. CarriesPY-TEST-2(isolation) andPY-TEST-5(meaningful assertions) into the web layer.
10. Serving & Lifecycle
- FASTAPI-RUN-1 (MUST): Serve with Uvicorn (an ASGI server); in production run under a process
manager/container with multiple workers. Do not use the dev
--reloadserver in production. - FASTAPI-RUN-2 (MUST): Expose a health/readiness endpoint, and ensure the
lifespanshutdown path drains in-flight work and closes pools/clients (ties toFASTAPI-STRUCT-3).
Resolved Decisions
Settled per the verified cross-platform best practice (kept consistent with nodejs.md v1.1):
| # | Axis | Decision |
| Q1 | ORM / data layer | ✅ SQLAlchemy 2.0 (async) + Alembic recommended (or SQLModel); ORM recommended not mandated, but migrations + the data-layer boundary are required (FASTAPI-STRUCT-5). |
| Q2 | Auth scheme | ✅ Stateless JWT bearer (OAuth2PasswordBearer) as the default, enforced via dependencies; httpOnly session cookies (browser apps) and external IdP/OAuth2 (larger systems) are sanctioned alternatives (FASTAPI-SEC-1). |
| Q3 | API versioning | ✅ URI versioning /v1 via APIRouter(prefix="/v1") for public APIs; header/media-type acceptable; internal APIs may defer (FASTAPI-DOC-2). |
| Q4 | Depth | ✅ Lean, consistent with the other standards. |
Inherited from the Python core: 3.12 floor, mypy --strict, uv, Ruff, Google docstrings, ≥80%
changed-code coverage + flag weak tests, FRAMEWORK-AREA-N IDs + severity mapping.
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.

