FastAPI best practices for building production Python backends. Use when building REST APIs, async endpoints, Pydantic models, dependency injection, middleware, or any FastAPI server.
Scanned 6/3/2026
Install via CLI
openskills install cohen-liel/hivemind---
name: fastapi-backend
description: FastAPI best practices for building production Python backends. Use when building REST APIs, async endpoints, Pydantic models, dependency injection, middleware, or any FastAPI server.
---
# FastAPI Backend Patterns
## Project Structure
```
app/
main.py # FastAPI app, lifespan, middleware
config.py # Pydantic Settings, env vars
models/ # SQLAlchemy ORM models
schemas/ # Pydantic request/response schemas
routers/ # APIRouter per domain (auth, users, posts)
services/ # Business logic (no DB or HTTP here)
deps.py # Shared dependencies (get_db, get_current_user)
database.py # Engine, SessionLocal, Base
```
## Core Patterns
### App setup with lifespan
```python
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# startup
await database.connect()
yield
# shutdown
await database.disconnect()
app = FastAPI(lifespan=lifespan)
```
### Dependency injection
```python
# deps.py
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
) -> User:
...
```
### Router pattern
```python
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
user = await db.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
```
### Error handling
```python
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
return JSONResponse(status_code=400, content={"detail": str(exc)})
```
### Pydantic schemas
```python
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=8)
name: str = Field(max_length=100)
class UserResponse(BaseModel):
id: int
email: str
name: str
model_config = ConfigDict(from_attributes=True)
```
## Rules
- Always use async def for endpoints
- Validate ALL input with Pydantic (never trust raw dicts)
- Use HTTPException with specific status codes (not 500 for everything)
- Never put business logic in route handlers — use service layer
- Use response_model to control what's returned (never expose passwords)
- Add CORS middleware for browser clients
- Use Depends() for database sessions — never create sessions manually

No comments yet. Be the first to comment!