Skip to content
Back to skills

Fastapi

ASecurity

Expert skill for FastAPI web framework development. Covers ASGI/Starlette foundation, Pydantic v2 integration, dependency injection, path operations, automatic OpenAPI generation, async/await patterns, middleware, security (OAuth2, JWT), testing (TestClient, httpx), SQLAlchemy/SQLModel integration, and deployment. WHEN: \"FastAPI\", \"Starlette\", \"ASGI\", \"Pydantic\", \"Depends\", \"APIRouter\", \"path operation\", \"response_model\", \"OpenAPI auto-docs\", \"Swagger UI\", \"FastAPI middle...

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
databasespythonrustgosqlfastapidockertestingdebugginggitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 24, 2026

npx -y skills add chrishuffman5/domain-expert --skill fastapi --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Fastapi?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Fastapi
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/chrishuffman5-fastapi/badge)](https://www.skillsdirectory.com/skills/chrishuffman5-fastapi)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: fastapi
description: "Expert skill for FastAPI web framework development. Covers ASGI/Starlette foundation, Pydantic v2 integration, dependency injection, path operations, automatic OpenAPI generation, async/await patterns, middleware, security (OAuth2, JWT), testing (TestClient, httpx), SQLAlchemy/SQLModel integration, and deployment. WHEN: \"FastAPI\", \"Starlette\", \"ASGI\", \"Pydantic\", \"Depends\", \"APIRouter\", \"path operation\", \"response_model\", \"OpenAPI auto-docs\", \"Swagger UI\", \"FastAPI middleware\", \"FastAPI dependency injection\", \"FastAPI testing\", \"TestClient\", \"BackgroundTasks\", \"SQLModel\", \"uvicorn\", \"FastAPI WebSocket\", \"FastAPI security\", \"OAuth2PasswordBearer\". Do NOT use for general Python scripting, automation, or CLI-tool questions unrelated to the FastAPI framework — that's the `cli-scripting` plugin's `python` skill."
license: MIT
---

# FastAPI

This skill covers FastAPI development. FastAPI is a modern, high-performance Python web framework built on Starlette (ASGI) and Pydantic v2. It provides automatic OpenAPI documentation, type-driven request validation, a powerful dependency injection system, and first-class async support. FastAPI follows rolling 0.x releases -- there is no version-specific reference material.

## How to Approach Tasks

1. **Classify** the request:
   - **Architecture** -- Load `references/architecture.md` for ASGI internals, Starlette foundation, Pydantic v2 models, dependency injection mechanics, request lifecycle, OpenAPI generation, response handling
   - **Best practices** -- Load `references/best-practices.md` for project structure, repository/service pattern, auth flows, database patterns, testing, deployment, caching, error handling
   - **Troubleshooting** -- Load `references/diagnostics.md` for 422 validation errors, Pydantic v1-to-v2 migration, async pitfalls, dependency resolution failures, performance profiling

2. **Gather context** -- Check Python version (3.11+ recommended), FastAPI version, Pydantic v1 vs v2, sync vs async database driver, deployment target (Docker, bare metal, serverless).

3. **Load context** -- Read the relevant reference file before answering.

4. **Analyze** -- Apply FastAPI-specific reasoning. Consider Pydantic model design, dependency graph complexity, async vs sync trade-offs, and OpenAPI schema impact.

5. **Recommend** -- Provide concrete Python code examples with explanations. Always qualify trade-offs.

6. **Verify** -- Suggest validation steps: run tests with `pytest`, check OpenAPI schema at `/docs`, verify dependency resolution, confirm async behavior.

## Core Architecture

### ASGI and Starlette Foundation

FastAPI is a Starlette application. Every `FastAPI()` instance inherits Starlette's ASGI interface, routing, middleware stack, and request/response classes. ASGI replaces WSGI by supporting long-lived connections (WebSockets, SSE) and native async.

```python
from fastapi import FastAPI, Request

app = FastAPI()

# Direct access to Starlette primitives
@app.get("/raw")
async def raw_access(request: Request) -> dict:
    return {
        "method": request.method,
        "client": request.client,
        "scope_type": request.scope["type"],
    }
```

**Starlette classes exposed by FastAPI:** `APIRouter` (from `Router`), `Request`/`Response`, `BackgroundTasks`, `WebSocket`, `StaticFiles`, `TestClient`.

### Pydantic v2 Integration

FastAPI uses Pydantic v2 for all validation and serialization. The v2 engine is Rust-based (`pydantic-core`), providing 5-50x faster validation than v1.

```python
from pydantic import BaseModel, Field, field_validator, model_validator, ConfigDict
from typing import Annotated, Self

class UserCreate(BaseModel):
    model_config = ConfigDict(str_strip_whitespace=True)

    username: Annotated[str, Field(min_length=3, max_length=50, pattern=r"^[a-z0-9_]+$")]
    email: str
    age: Annotated[int, Field(ge=18, le=120)]

class OrderCreate(BaseModel):
    quantity: int
    unit_price: float
    total: float

    @field_validator("quantity")
    @classmethod
    def quantity_positive(cls, v: int) -> int:
        if v <= 0:
            raise ValueError("quantity must be positive")
        return v

    @model_validator(mode="after")
    def check_total(self) -> Self:
        expected = self.quantity * self.unit_price
        if abs(self.total - expected) > 0.01:
            raise ValueError(f"total {self.total} does not match {expected:.2f}")
        return self
```

**Key v2 changes:** `model_config = ConfigDict(...)` replaces inner `Config` class. `from_attributes=True` replaces `orm_mode=True`. `model_dump()` replaces `dict()`. `Field(exclude=True)` for serialization control.

### Dependency Injection

FastAPI's DI system resolves dependencies per-request via `Depends()`. Dependencies are cached within the same request, support async, and compose into sub-dependency graphs.

```python
from fastapi import Depends, Query
from typing import Annotated

class PaginationParams:
    def __init__(self, page: int = Query(1, ge=1), size: int = Query(20, ge=1, le=100)):
        self.page = page
        self.size = size
        self.offset = (page - 1) * size

Pagination = Annotated[PaginationParams, Depends()]

# Yield dependencies for resource management (DB sessions)
async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with AsyncSessionLocal() as session:
        try:
            yield session
            await session.commit()
        except Exception:
            await session.rollback()
            raise

DB = Annotated[AsyncSession, Depends(get_db)]

# Router-level dependencies apply to all routes
router = APIRouter(prefix="/admin", dependencies=[Depends(require_admin)])
```

### Path Operations

```python
from fastapi import APIRouter, Path, Query, Body, status

router = APIRouter(prefix="/items", tags=["items"])

@router.get("/{item_id}", response_model=ItemRead, status_code=200)
async def get_item(
    item_id: Annotated[int, Path(ge=1)],
    include_deleted: Annotated[bool, Query()] = False,
) -> ItemRead:
    ...

@router.post("/", status_code=status.HTTP_201_CREATED)
async def create_item(item: ItemCreate, db: DB) -> ItemRead:
    ...
```

**Parameter sources:** Path params from URL template, Query params from simple types not in the path, Body from Pydantic models, plus `Header()`, `Cookie()`, `Form()`, `File()`.

**Response models:** Use `response_model=` parameter for explicit type narrowing and field filtering, or return type annotations for cleaner signatures. `response_model` runs automatic validation; return type annotations do not.

### OpenAPI Auto-Generation

FastAPI generates OpenAPI 3.1 specs from your code. Interactive docs at `/docs` (Swagger UI) and `/redoc`.

```python
app = FastAPI(
    title="My API",
    version="1.0.0",
    docs_url="/api/docs",
    redoc_url="/api/redoc",
    openapi_url="/api/openapi.json",
)

# Hide internal endpoints
@app.get("/internal/metrics", include_in_schema=False)
async def metrics(): ...

# Disable docs in production
app = FastAPI(docs_url=None, redoc_url=None)
```

### Async/Await

```python
# async def: for awaitable I/O (async DB, httpx, aiofiles)
@app.get("/async")
async def async_endpoint(db: DB) -> list[ItemRead]:
    result = await db.execute(select(Item))
    return result.scalars().all()

# def: for sync/blocking code -- FastAPI runs these in a threadpool automatically
@app.get("/sync")
def sync_endpoint() -> dict:
    return requests.get("https://external.api/data").json()
```

**Rule:** Use `async def` with awaitable I/O. Use `def` for blocking libraries (requests, psycopg2, boto3). Never call blocking I/O inside `async def` without wrapping in a threadpool.

### Middleware

```python
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware

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

# Custom middleware
class RequestIDMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        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)
```

For high-throughput scenarios, write pure ASGI middleware instead of `BaseHTTPMiddleware` (which buffers responses).

### Security

FastAPI provides `OAuth2PasswordBearer`, `APIKeyHeader`, `APIKeyQuery`, and `SecurityScopes` for building auth flows.

```python
from fastapi.security import OAuth2PasswordBearer
import jwt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")

async def get_current_user(
    token: Annotated[str, Depends(oauth2_scheme)], db: DB
) -> User:
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    user = await db.get(User, int(payload["sub"]))
    if not user:
        raise HTTPException(status_code=401, detail="Invalid credentials")
    return user

CurrentUser = Annotated[User, Depends(get_current_user)]
```

### Testing

```python
from fastapi.testclient import TestClient
from httpx import AsyncClient, ASGITransport

# Sync testing
client = TestClient(app)
response = client.get("/items/1")
assert response.status_code == 200

# Async testing
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
    response = await client.post("/users/", json={"email": "test@example.com"})
    assert response.status_code == 201

# Dependency overrides for isolation
app.dependency_overrides[get_current_user] = lambda: mock_user
app.dependency_overrides[get_db] = lambda: test_session
```

### Database Integration

FastAPI works with async SQLAlchemy 2.0 (via `asyncpg`/`aiosqlite`) and SQLModel (Pydantic + SQLAlchemy hybrid).

```python
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

engine = create_async_engine("postgresql+asyncpg://...", pool_size=20)
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
```

### Lifespan Events

```python
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    app.state.http_client = httpx.AsyncClient(timeout=30.0)
    yield
    # Shutdown
    await app.state.http_client.aclose()

app = FastAPI(lifespan=lifespan)
```

## Key Patterns

| Pattern | When to Use |
|---|---|
| `Depends()` with yield | Database sessions, HTTP clients, any resource needing cleanup |
| `Annotated[T, Depends()]` | Reusable dependency type aliases (cleaner signatures) |
| `response_model` | Filtering ORM objects, returning different type than function return |
| `APIRouter` with `prefix`/`tags` | Organizing routes by resource or domain |
| `BackgroundTasks` | Fire-and-forget tasks (email, audit log) after response |
| Sub-applications via `app.mount()` | Separate OpenAPI schemas per version |
| `include_router` with `prefix` | Single OpenAPI schema, grouped routes |

## Error Handling

```python
from fastapi import HTTPException
from fastapi.exceptions import RequestValidationError

# Raise HTTP errors
raise HTTPException(status_code=404, detail="Item not found")

# Custom exception handlers
@app.exception_handler(RequestValidationError)
async def validation_handler(request, exc):
    return JSONResponse(status_code=422, content={"errors": exc.errors()})
```

## Deployment

| Configuration | Command |
|---|---|
| Development | `uvicorn app.main:app --reload --port 8000` |
| Production (single) | `uvicorn app.main:app --host 0.0.0.0 --workers 1` |
| Production (multi-core) | `gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker` |
| Docker | Gunicorn + UvicornWorker, non-root user, multi-stage build |

**Worker formula:** `(2 * CPU_COUNT) + 1` for I/O-bound async apps.

## Anti-Patterns

1. **Blocking I/O in `async def`** -- Blocks the event loop. Use `def` (threadpool) or wrap with `anyio.to_thread.run_sync()`.
2. **Skipping `expire_on_commit=False`** -- Causes `MissingGreenlet` errors when accessing ORM attributes after commit in async context.
3. **Global mutable state** -- Each Gunicorn worker runs a separate process. Use Redis or database for shared state.
4. **`response_model` with ORM objects + missing `from_attributes=True`** -- Results in empty responses or validation errors.
5. **Overly deep dependency chains** -- FastAPI resolves the full graph per request. Keep dependency depth under 4-5 levels.

## Reference Files

Load these for deep knowledge on specific topics:

- `references/architecture.md` -- ASGI internals, Starlette foundation, Pydantic v2 (BaseModel, Field, validators, discriminated unions), dependency injection (Depends, yield, sub-dependencies, override), request lifecycle, OpenAPI generation, response model handling. **Load when:** architecture questions, Pydantic model design, DI mechanics, OpenAPI customization.
- `references/best-practices.md` -- Project structure, repository/service pattern, auth flows (JWT, OAuth2 scopes), database patterns (async SQLAlchemy, session management, Alembic), testing (TestClient, dependency overrides, database isolation), deployment (Uvicorn, Gunicorn workers, Docker), caching, background tasks, error handling. **Load when:** "how should I structure", auth implementation, database setup, testing strategy, deployment configuration.
- `references/diagnostics.md` -- Common errors (422 validation, Pydantic v1-to-v2 migration, async pitfalls, dependency resolution), debugging techniques, performance profiling, async database issues. **Load when:** troubleshooting errors, debugging validation failures, diagnosing performance problems.

Files in this skill

  • SKILL.md13.5 KB
  • references/architecture.md25.8 KB
  • references/best-practices.md25.7 KB
  • references/diagnostics.md14.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…