- Python 3.11+. Use modern syntax:
match/case,typealiases,ExceptionGroup. - Type hints everywhere. All function signatures, return types, and class attributes. Use
from __future__ import annotationsfor forward references. - Pydantic v2 for data validation.
BaseModelfor schemas,model_validatorfor complex validation. Never use raw dicts for API I/O. - Async by default. Use
async deffor route handlers and DB operations. Useasyncio.gatherfor concurrent I/O. - No global mutable state. Use dependency injection via FastAPI's
Depends(). - Naming. snake_case for functions/variables. PascalCase for classes. UPPER_SNAKE for constants.
- Router per domain.
app/routers/users.py,app/routers/items.py. Mount withapp.include_router(). - Pydantic schemas for I/O. Separate
Create,Update,Responseschemas. Never expose ORM models directly. - Dependency injection. DB sessions, auth, config — all via
Depends(). Define inapp/dependencies.py. - Status codes. Use
status.HTTP_201_CREATEDfor creates,HTTP_204_NO_CONTENTfor deletes. RaiseHTTPExceptionwith proper codes. - Background tasks. Use
BackgroundTasksfor fire-and-forget. Use Celery/ARQ for durable jobs. - Middleware. CORS, request logging, error handling. Define in
app/middleware.py.
app/
main.py # FastAPI app instance + startup
core/
config.py # Settings via pydantic-settings
security.py # Auth utilities
routers/ # APIRouter modules
models/ # SQLAlchemy/SQLModel ORM models
schemas/ # Pydantic request/response models
dependencies.py # Shared Depends() callables
middleware.py # Middleware stack
tests/
conftest.py # Fixtures (test client, DB)
test_*.py # Test modules
- SQLAlchemy 2.0 style.
select()notquery(). Mapped classes withMapped[]annotations. - Alembic for migrations. Auto-generate with
alembic revision --autogenerate. Never edit the DB schema manually. - Session management. Async sessions via
async_sessionmaker. Yield in dependency. - Connection pooling. Configure
pool_size,max_overflowin production.
- pytest + httpx. Use
AsyncClientwithappfor integration tests. - Fixtures for DB. Create test database, run migrations, yield session, rollback.
- Factory pattern for test data. Use
factory_boyor simple fixture functions. - Test the API, not internals. Call endpoints via client, assert response shape + status.
- Synchronous DB calls in async handlers → blocks the event loop
- Raw SQL without parameterization → SQL injection risk
- Returning ORM models from endpoints → use Pydantic response models
- Missing
asyncon route handlers with I/O → blocks worker threads - Hardcoded secrets → use environment variables via pydantic-settings
- Missing input validation → always validate via Pydantic schemas