FastAPI Production Patterns

v1.0.0

Production FastAPI patterns with Pydantic v2, async endpoints, OAuth2/JWT, dependency injection, testing, and Kubernetes deployment

0· 549·3 current·3 all-time
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Skill name/description (FastAPI production patterns) align with the SKILL.md content: migration notes, async/sync rules, OAuth2/JWT examples, testing, Docker/Kubernetes guidance and health endpoints. Nothing requested (no env vars, no installs) is unexpected for this doc-oriented skill.
Instruction Scope
The SKILL.md stays within the stated purpose (coding patterns and deployment guidance). However there are small issues in the instructions: a hard-coded SECRET_KEY appears in the JWT example; a broad bare 'except:' is used (swallows errors); the Dockerfile CMD sets 4 Gunicorn workers while the text recommends '1 worker per container' for Kubernetes — this is a contradictory recommendation. These are correctness/security concerns in examples, not evidence of scope creep.
Install Mechanism
Instruction-only skill with no install spec and no code files — nothing is written to disk or fetched at install time. Lowest-risk install surface.
Credentials
The skill requests no environment variables or credentials. Still, examples reference secrets and connection strings (e.g., SECRET_KEY, database URLs) inline; users should not copy these literal values into production and should instead use proper secret/config management. No unexplained credential requests are present.
Persistence & Privilege
always is false and there are no install scripts or config-file writes. The skill does not request persistent presence or modify other skills/settings.
Assessment
This skill is an instruction-only pattern guide and is internally coherent, but treat the examples as illustrative — do not paste them into production without review. Specific things to check before using: replace hard-coded secrets (SECRET_KEY) with environment/secret-store values; catch and handle explicit JWT/auth exceptions rather than using a bare 'except:'; reconcile the worker-count guidance (Dockerfile uses 4 workers but the text recommends one per container for Kubernetes); verify CORS, auth, and DB connection examples follow your org's security practices. Because this skill contains code snippets (and some insecure patterns), review and test any code copied from it before deployment.

Like a lobster shell, security has layers — review code before you run it.

latestvk97e7x34x9ksewrmct6mvxt8ah829pf7
549downloads
0stars
1versions
Updated 1mo ago
v1.0.0
MIT-0

FastAPI Production Patterns

Description

Modern FastAPI development patterns for 2026, covering the full spectrum from Pydantic v2 migration to production deployment. Validated against 15+ production sources with 0.95 confidence. This skill keeps you on the current side of breaking changes and equips you with battle-tested patterns for async, security, testing, and performance.

Usage

Install this skill to get production-ready FastAPI patterns including:

  • Pydantic v2 migration guide (breaking changes, 4-17x performance gains)
  • Async vs sync endpoint decision rules
  • OAuth2 + JWT authentication patterns
  • Dependency override testing strategies
  • Docker + Kubernetes deployment with health probes

When working on FastAPI projects, this skill provides context for:

  • Migrating from Pydantic v1 to v2 without breaking existing code
  • Setting up proper lifespan events instead of deprecated @app.on_event()
  • Structuring tests with TestClient (sync) and AsyncClient (async)
  • Configuring Gunicorn + Uvicorn workers for production

Key Patterns

Pydantic v2 Migration

# BEFORE (Pydantic v1 — deprecated)
from pydantic import BaseModel, validator

class User(BaseModel):
    name: str

    @validator('name')
    def name_must_not_be_empty(cls, v):
        if not v:
            raise ValueError('name cannot be empty')
        return v

# AFTER (Pydantic v2 — current)
from pydantic import BaseModel, field_validator

class User(BaseModel):
    name: str

    @field_validator('name')
    @classmethod
    def name_must_not_be_empty(cls, v):
        if not v:
            raise ValueError('name cannot be empty')
        return v

Method renames (v1 to v2): parse_obj() -> model_validate(), dict() -> model_dump(), json() -> model_dump_json(), orm_mode = True -> model_config = ConfigDict(from_attributes=True), conint(ge=0) -> Annotated[int, Field(ge=0)]

Lifespan Events (Modern Pattern)

from contextlib import asynccontextmanager
from fastapi import FastAPI

ml_models = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup: load resources
    ml_models["answer"] = load_ml_model()
    yield
    # Shutdown: release resources
    ml_models.clear()

app = FastAPI(lifespan=lifespan)

Do NOT use deprecated @app.on_event(). Use lifespan for: DB connection pools, ML models, resource cleanup.

Async Decision Rule

# Use async def for: asyncpg, motor, httpx (non-blocking I/O)
@app.get('/users/')
async def get_users():
    users = await async_db.fetch('SELECT * FROM users')
    return users

# Use def for: psycopg2, pymongo, requests (blocking libs)
# FastAPI automatically runs def endpoints in a threadpool
@app.get('/users/sync')
def get_users_sync():
    return sync_db.query('SELECT * FROM users')

Rule of thumb: If unsure, use def. FastAPI handles the threadpool for you.

OAuth2 + JWT Authentication

from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jose import jwt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"

async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        if not username:
            raise HTTPException(status_code=401)
        return username
    except:
        raise HTTPException(status_code=401)

CORS (Never Use wildcard in Production)

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],  # NOT ["*"]
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Async Testing with httpx

import pytest
from httpx import ASGITransport, AsyncClient

@pytest.mark.anyio
async def test_async_endpoint():
    async with AsyncClient(
        transport=ASGITransport(app=app),
        base_url="http://test"
    ) as ac:
        response = await ac.get("/")
    assert response.status_code == 200

Dependency Overrides for Mocking

async def override_get_db():
    db = Database("sqlite:///:memory:")
    yield db
    await db.disconnect()

def test_with_mock_db():
    app.dependency_overrides[get_db] = override_get_db
    client = TestClient(app)
    response = client.get("/users/")
    assert response.status_code == 200
    app.dependency_overrides = {}  # Always clean up

Production Dockerfile

FROM python:3.11-slim
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD ["gunicorn", "app.main:app", "--workers", "4",
     "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:80"]

Workers: 1 per CPU core on a single server. For Kubernetes: 1 worker per container, scale at cluster level.

Health Check Endpoints

@app.get("/health")
async def health_check():
    """Liveness: is the process running?"""
    return {"status": "healthy"}

@app.get("/ready")
async def readiness_check():
    """Readiness: can it handle traffic?"""
    try:
        await database.execute("SELECT 1")
        return {"status": "ready", "database": "ok"}
    except Exception as e:
        raise HTTPException(status_code=503, detail=str(e))

Performance Quick Wins

# Connection pooling: 2-3x throughput improvement
database = Database("postgresql://user:pass@localhost/db", min_size=5, max_size=20)

# Response caching: 90%+ database load reduction
@cache(expire=60)
async def get_user(user_id: int):
    return await db.fetch_one(...)

# Async middleware: 10-30% latency reduction
@app.middleware("http")
async def async_middleware(request, call_next):
    return await call_next(request)  # NOT blocking def

Common Pitfall: Blocking Inside Async

# WRONG: blocks the event loop
@app.get("/data")
async def get_data():
    response = requests.get("https://api.com")  # Blocks!

# CORRECT: use async library
import httpx
@app.get("/data")
async def get_data():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.com")

Tools & References


Published by MidOS — MCP Community Library

Comments

Loading comments...