fastapi-advanced

FastAPI Advanced Patterns ()

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "fastapi-advanced" with this command: npx skills add yonatangross/orchestkit/yonatangross-orchestkit-fastapi-advanced

FastAPI Advanced Patterns ()

Production-ready FastAPI patterns for modern Python backends.

Lifespan Management ()

Modern Lifespan Context Manager

from contextlib import asynccontextmanager from fastapi import FastAPI from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession import redis.asyncio as redis

@asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan with resource management.""" # Startup app.state.db_engine = create_async_engine( settings.database_url, pool_size=5, max_overflow=10, ) app.state.redis = redis.from_url(settings.redis_url)

# Health check connections
async with app.state.db_engine.connect() as conn:
    await conn.execute(text("SELECT 1"))
await app.state.redis.ping()

yield  # Application runs

# Shutdown
await app.state.db_engine.dispose()
await app.state.redis.close()

app = FastAPI(lifespan=lifespan)

Lifespan with Services

from app.services import EmbeddingsService, LLMService

@asynccontextmanager async def lifespan(app: FastAPI): # Initialize services app.state.embeddings = EmbeddingsService( model=settings.embedding_model, batch_size=100, ) app.state.llm = LLMService( providers=["openai", "anthropic"], default="anthropic", )

# Warm up models (optional)
await app.state.embeddings.warmup()

yield

# Cleanup
await app.state.embeddings.close()
await app.state.llm.close()

Dependency Injection Patterns

Database Session

from typing import AsyncGenerator from sqlalchemy.ext.asyncio import AsyncSession from fastapi import Depends, Request

async def get_db(request: Request) -> AsyncGenerator[AsyncSession, None]: """Yield database session from app state.""" async with AsyncSession( request.app.state.db_engine, expire_on_commit=False, ) as session: try: yield session await session.commit() except Exception: await session.rollback() raise

Service Dependencies

from functools import lru_cache

class AnalysisService: def init( self, db: AsyncSession, embeddings: EmbeddingsService, llm: LLMService, ): self.db = db self.embeddings = embeddings self.llm = llm

def get_analysis_service( db: AsyncSession = Depends(get_db), request: Request = None, ) -> AnalysisService: return AnalysisService( db=db, embeddings=request.app.state.embeddings, llm=request.app.state.llm, )

@router.post("/analyses") async def create_analysis( data: AnalysisCreate, service: AnalysisService = Depends(get_analysis_service), ): return await service.create(data)

Cached Dependencies

from functools import lru_cache from pydantic_settings import BaseSettings

class Settings(BaseSettings): database_url: str redis_url: str api_key: str

model_config = {"env_file": ".env"}

@lru_cache def get_settings() -> Settings: return Settings()

Usage in dependencies

def get_db_url(settings: Settings = Depends(get_settings)) -> str: return settings.database_url

Authenticated User

from fastapi import Depends, HTTPException, Security from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()

async def get_current_user( credentials: HTTPAuthorizationCredentials = Security(security), db: AsyncSession = Depends(get_db), ) -> User: token = credentials.credentials payload = decode_jwt(token)

user = await db.get(User, payload["sub"])
if not user:
    raise HTTPException(401, "Invalid credentials")
return user

async def get_admin_user( user: User = Depends(get_current_user), ) -> User: if not user.is_admin: raise HTTPException(403, "Admin access required") return user

Middleware Patterns

Request ID Middleware

import uuid from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request

class RequestIDMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): request_id = request.headers.get("X-Request-ID", str(uuid.uuid4())) request.state.request_id = request_id

    response = await call_next(request)
    response.headers["X-Request-ID"] = request_id
    return response

app.add_middleware(RequestIDMiddleware)

Timing Middleware

import time from starlette.middleware.base import BaseHTTPMiddleware

class TimingMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): start = time.perf_counter() response = await call_next(request) duration = time.perf_counter() - start

    response.headers["X-Response-Time"] = f"{duration:.3f}s"
    return response

Structured Logging Middleware

import structlog from starlette.middleware.base import BaseHTTPMiddleware

logger = structlog.get_logger()

class LoggingMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): log = logger.bind( request_id=getattr(request.state, "request_id", None), method=request.method, path=request.url.path, )

    try:
        response = await call_next(request)
        log.info(
            "request_completed",
            status_code=response.status_code,
        )
        return response
    except Exception as exc:
        log.exception("request_failed", error=str(exc))
        raise

CORS Configuration

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "PATCH"], allow_headers=["*"], expose_headers=["X-Request-ID", "X-Response-Time"], )

Settings with Pydantic

from pydantic import Field, field_validator, PostgresDsn from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, )

# Database
database_url: PostgresDsn
db_pool_size: int = Field(default=5, ge=1, le=20)
db_max_overflow: int = Field(default=10, ge=0, le=50)

# Redis
redis_url: str = "redis://localhost:6379"

# API
api_key: str = Field(min_length=32)
debug: bool = False

# LLM
openai_api_key: str | None = None
anthropic_api_key: str | None = None

@field_validator("database_url", mode="before")
@classmethod
def validate_database_url(cls, v: str) -> str:
    if v and "+asyncpg" not in v:
        return v.replace("postgresql://", "postgresql+asyncpg://")
    return v

@property
def async_database_url(self) -> str:
    return str(self.database_url)

Exception Handlers

from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from sqlalchemy.exc import IntegrityError from app.core.exceptions import ProblemException

@app.exception_handler(ProblemException) async def problem_exception_handler(request: Request, exc: ProblemException): return JSONResponse( status_code=exc.status_code, content=exc.to_problem_detail(), media_type="application/problem+json", )

@app.exception_handler(IntegrityError) async def integrity_error_handler(request: Request, exc: IntegrityError): return JSONResponse( status_code=409, content={ "type": "https://api.example.com/problems/conflict", "title": "Conflict", "status": 409, "detail": "Resource already exists or constraint violated", }, media_type="application/problem+json", )

Response Optimization

from fastapi.responses import ORJSONResponse

Use orjson for faster JSON serialization

app = FastAPI(default_response_class=ORJSONResponse)

Streaming response

from fastapi.responses import StreamingResponse

@router.get("/export") async def export_data(): async def generate(): async for chunk in fetch_large_dataset(): yield json.dumps(chunk) + "\n"

return StreamingResponse(
    generate(),
    media_type="application/x-ndjson",
)

Health Checks

from fastapi import APIRouter

health_router = APIRouter(tags=["health"])

@health_router.get("/health") async def health_check(request: Request): checks = {}

# Database
try:
    async with request.app.state.db_engine.connect() as conn:
        await conn.execute(text("SELECT 1"))
    checks["database"] = "healthy"
except Exception as e:
    checks["database"] = f"unhealthy: {e}"

# Redis
try:
    await request.app.state.redis.ping()
    checks["redis"] = "healthy"
except Exception as e:
    checks["redis"] = f"unhealthy: {e}"

status = "healthy" if all(v == "healthy" for v in checks.values()) else "unhealthy"
return {"status": status, "checks": checks}

Anti-Patterns (FORBIDDEN)

NEVER use global state

db_session = None # Global mutable state!

NEVER block the event loop

def sync_db_query(): # Blocking in async context! return session.query(User).all()

NEVER skip dependency injection

@router.get("/users") async def get_users(): db = create_session() # Creating session in route! return db.query(User).all()

NEVER ignore lifespan cleanup

@asynccontextmanager async def lifespan(app: FastAPI): app.state.pool = create_pool() yield # Missing cleanup! Pool never closed

Key Decisions

Decision Recommendation

Lifespan Use asynccontextmanager (not events)

Dependencies Class-based services with DI

Settings Pydantic Settings with .env

Response ORJSONResponse for performance

Middleware Order: CORS → RequestID → Timing → Logging

Health Check all critical dependencies

Available Scripts

scripts/create-fastapi-app.md

  • Context-aware FastAPI application generator

  • Auto-detects: Python version, database type, Redis usage, project structure

  • Usage: /create-fastapi-app [app-name]

  • Uses $ARGUMENTS and !command for project-specific configuration

  • Generates production-ready app with detected dependencies

assets/fastapi-app-template.py

  • Static FastAPI application template

Related Skills

  • clean-architecture

  • Service layer patterns

  • database-schema-designer

  • SQLAlchemy models

  • observability-monitoring

  • Logging and metrics

Capability Details

lifespan

Keywords: lifespan, startup, shutdown, asynccontextmanager Solves:

  • FastAPI startup/shutdown

  • Resource management in FastAPI

dependencies

Keywords: dependency injection, Depends, get_db, service dependency Solves:

  • FastAPI dependency injection patterns

  • Reusable dependencies

middleware

Keywords: middleware, request id, timing, cors, logging middleware Solves:

  • Custom FastAPI middleware

  • Request/response interceptors

settings

Keywords: settings, pydantic settings, env, configuration Solves:

  • FastAPI configuration management

  • Environment variables

health-checks

Keywords: health check, readiness, liveness, health endpoint Solves:

  • Kubernetes health checks

  • Service health monitoring

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

responsive-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

domain-driven-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

dashboard-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

rag-retrieval

No summary provided by upstream source.

Repository SourceNeeds Review