# Fastapi Advanced

> When to activate: FastAPI advanced patterns, middleware, lifespan, OpenAPI customization, rate limiting, CORS, file uploads

- Skill: `mattakushi432/fastapi-advanced` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/fastapi-advanced`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/fastapi-advanced/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/fastapi-advanced

---


# Advanced FastAPI Patterns

## Lifespan (startup/shutdown)
```python
from contextlib import asynccontextmanager
from fastapi import FastAPI

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    await db_pool.start()
    await redis.connect()
    logger.info("Application started")
    
    yield  # app is running
    
    # Shutdown
    await db_pool.close()
    await redis.disconnect()
    logger.info("Application stopped")

app = FastAPI(lifespan=lifespan)
```

## OpenAPI Customization
```python
from fastapi.openapi.utils import get_openapi

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    
    schema = get_openapi(
        title="My API",
        version="1.0.0",
        description="Production API documentation",
        routes=app.routes,
    )
    
    # Add security scheme
    schema["components"]["securitySchemes"] = {
        "BearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"}
    }
    schema["security"] = [{"BearerAuth": []}]
    
    app.openapi_schema = schema
    return schema

app.openapi = custom_openapi
```

## File Uploads
```python
from fastapi import UploadFile, File
import aiofiles

ALLOWED_TYPES = {"image/jpeg", "image/png", "application/pdf"}
MAX_FILE_SIZE = 10 * 1024 * 1024  # 10MB

@router.post("/upload")
async def upload_file(
    file: UploadFile = File(...),
    current_user: User = Depends(get_current_user),
) -> dict:
    # Validate content type
    if file.content_type not in ALLOWED_TYPES:
        raise HTTPException(400, f"File type {file.content_type} not allowed")
    
    # Stream to check size without loading all into memory
    contents = b""
    async for chunk in file:
        contents += chunk
        if len(contents) > MAX_FILE_SIZE:
            raise HTTPException(413, "File too large")
    
    # Save
    dest = Path(f"uploads/{uuid4()}_{file.filename}")
    async with aiofiles.open(dest, "wb") as out:
        await out.write(contents)
    
    return {"filename": file.filename, "size": len(contents), "path": str(dest)}
```

## Middleware Stack
```python
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.middleware.gzip import GZipMiddleware

# Order matters: outermost first
app.add_middleware(GZipMiddleware, minimum_size=1000)
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.cors_origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(TrustedHostMiddleware, allowed_hosts=["api.example.com", "localhost"])
```

## Custom Exception Handling
```python
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException

@app.exception_handler(RequestValidationError)
async def validation_error_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
    return JSONResponse(
        status_code=422,
        content={
            "error": "validation_error",
            "details": [
                {"field": ".".join(str(loc) for loc in err["loc"]), "message": err["msg"]}
                for err in exc.errors()
            ],
        },
    )

@app.exception_handler(StarletteHTTPException)
async def http_error_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
    return JSONResponse(
        status_code=exc.status_code,
        content={"error": exc.detail},
    )
```

