All skills
hieutrtr avatar

/fastapi-patterns

@566556d

FastAPI framework mechanics and advanced patterns. Use when configuring middleware, creating dependency injection chains, implementing WebSocket endpoints, customizing OpenAPI documentation, setting up CORS, building authentication dependencies (JWT validation, role-based access), implementing background tasks, or managing application lifespan (startup/shutdown). Does NOT cover basic endpoint CRUD or repository/service patterns (use python-backend-expert) or testing (use pytest-patterns).

Use this Skill: https://skilld.dev/gh/hieutrtr/ai1-skills/fastapi-patterns

This session only. Nothing lands on disk.

referencesmiddleware-examples.md

≈1.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Middleware Examples

Complete middleware implementations for FastAPI applications.


1. Request Logging Middleware

Logs every request with method, path, status code, and duration.

import time
import logging
from starlette.types import ASGIApp, Receive, Scope, Send

logger = logging.getLogger("api.access")


class RequestLoggingMiddleware:
    def __init__(self, app: ASGIApp) -> None:
        self.app = app

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        start = time.perf_counter()
        status_code = 500  # Default if response fails

        async def send_wrapper(message):
            nonlocal status_code
            if message["type"] == "http.response.start":
                status_code = message["status"]
            await send(message)

        try:
            await self.app(scope, receive, send_wrapper)
        finally:
            duration = time.perf_counter() - start
            method = scope.get("method", "?")
            path = scope.get("path", "?")
            logger.info(
                "request completed",
                extra={
                    "method": method,
                    "path": path,
                    "status_code": status_code,
                    "duration_ms": round(duration * 1000, 2),
                },
            )

2. Request ID Middleware

Assigns a unique ID to each request for tracing.

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


class RequestIdMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next) -> Response:
        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

3. Rate Limiting Middleware

Token bucket rate limiter with per-IP tracking.

import time
from collections import defaultdict
from starlette.types import ASGIApp, Receive, Scope, Send
from starlette.responses import JSONResponse


class RateLimitMiddleware:
    def __init__(
        self,
        app: ASGIApp,
        *,
        requests_per_minute: int = 60,
    ) -> None:
        self.app = app
        self.rate = requests_per_minute
        self.window = 60.0
        self.buckets: dict[str, list[float]] = defaultdict(list)

    def _get_client_ip(self, scope: Scope) -> str:
        # Check for proxy headers
        headers = dict(scope.get("headers", []))
        forwarded = headers.get(b"x-forwarded-for", b"").decode()
        if forwarded:
            return forwarded.split(",")[0].strip()
        client = scope.get("client")
        return client[0] if client else "unknown"

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        client_ip = self._get_client_ip(scope)
        now = time.time()

        # Clean old entries
        self.buckets[client_ip] = [
            t for t in self.buckets[client_ip] if now - t < self.window
        ]

        if len(self.buckets[client_ip]) >= self.rate:
            response = JSONResponse(
                status_code=429,
                content={"detail": "Rate limit exceeded", "code": "RATE_LIMITED"},
                headers={
                    "Retry-After": str(int(self.window)),
                    "X-RateLimit-Limit": str(self.rate),
                    "X-RateLimit-Remaining": "0",
                },
            )
            await response(scope, receive, send)
            return

        self.buckets[client_ip].append(now)
        await self.app(scope, receive, send)

4. Error Handling Middleware

Catches unhandled exceptions and returns consistent error responses.

import logging
import traceback
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse

logger = logging.getLogger("api.errors")


class ErrorHandlingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            return await call_next(request)
        except Exception as exc:
            logger.error(
                "Unhandled exception",
                extra={
                    "path": request.url.path,
                    "method": request.method,
                    "error": str(exc),
                    "traceback": traceback.format_exc(),
                },
            )
            return JSONResponse(
                status_code=500,
                content={
                    "detail": "Internal server error",
                    "code": "INTERNAL_ERROR",
                },
            )

5. CORS Configuration Examples

Development (Permissive)

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000", "http://localhost:5173"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Production (Restrictive)

app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "https://app.example.com",
        "https://admin.example.com",
    ],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    allow_headers=["Authorization", "Content-Type", "X-Request-ID"],
    expose_headers=["X-Request-ID", "X-RateLimit-Remaining"],
    max_age=600,  # Cache preflight for 10 minutes
)

Recommended Middleware Order

Add middleware in this order (last added = outermost = executes first):

# 5. Error handling (outermost — catches everything)
app.add_middleware(ErrorHandlingMiddleware)

# 4. Request timing/logging
app.add_middleware(RequestLoggingMiddleware)

# 3. Request ID assignment
app.add_middleware(RequestIdMiddleware)

# 2. Rate limiting
app.add_middleware(RateLimitMiddleware, requests_per_minute=100)

# 1. CORS (innermost — closest to routes)
app.add_middleware(CORSMiddleware, ...)

This ensures:

  • CORS headers are always included (even on errors)
  • Rate limiting runs before route processing
  • Every request gets an ID before logging
  • All requests are logged with timing
  • Unhandled exceptions are caught and formatted

Source: SKILL.md on GitHub

No alerts13d4 checks · Risk SAFE
  • Gen Agent Trust Hub13d

    The skill provides secure patterns for FastAPI development, including middleware, authentication, and dependency injection. It includes a surface for indirect prompt injection as it handles external web requests, but it promotes best practices like schema validation and restrictive CORS policies.

  • Socket13d

    No alerts

  • Snyk13d

    Risk: LOW · No issues

  • Runlayer7mo

    3 files scanned · No issues

Signed by skilld at 566556d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 8 months ago
compatibility
Python 3.12+, FastAPI 0.115+, Starlette
context
fork
All 1 allowed tools
Read Edit Write Bash(python:*) Bash(uvicorn:*)
Other metadata
metadata
{
  "author": "platform-team",
  "version": "1.0.0",
  "sdlc-phase": "implementation"
}

README badge

README badge for hieutrtr/ai1-skills/fastapi-patterns