# FastAPI Administrator and Developer Guide

This guide is the source-of-truth operational reference for **FastAPI** — the modern, high-performance Python web framework for building APIs with standard Python type hints. It is written for platform engineers, DevOps practitioners, security reviewers, architects, and developers who deploy, scale, extend, or contribute to FastAPI applications. The companion **User Guide** covers everyday usage — route definitions, request handling, and interactive docs. This Admin Guide covers what happens underneath: the ASGI middleware stack, OpenAPI schema generation internals, Pydantic integration mechanics, dependency injection resolution, security subsystem architecture, deployment topologies, performance tuning, and the complete configuration surface.

This document covers FastAPI **0.135.3** at commit `9653034` on the `master` branch of `tiangolo/fastapi`. Where the implementation deviates from external documentation or blog posts, the source wins; this guide reflects the source.

---

## Table of Contents

1. [Architecture Overview](#1-architecture-overview)
2. [System Requirements](#2-system-requirements)
3. [Configuration Reference](#3-configuration-reference)
4. [Deployment and Scaling](#4-deployment-and-scaling)
5. [Operations](#5-operations)
6. [Performance](#6-performance)
7. [Security](#7-security)
8. [Developer Internals](#8-developer-internals)
9. [Integration Points](#9-integration-points)
10. [Module Reference](#10-module-reference)
11. [Testing Strategy](#11-testing-strategy)
12. [Code Patterns and Conventions](#12-code-patterns-and-conventions)
13. [Troubleshooting](#13-troubleshooting)
14. [Quick Reference](#14-quick-reference)

---

## 1. Architecture Overview

FastAPI is a layered framework built on two foundational libraries: **Starlette** (the ASGI toolkit providing HTTP/WebSocket protocol handling, routing, middleware, and server integration) and **Pydantic v2** (the data validation and serialization layer that powers type-driven request parsing and OpenAPI schema generation). FastAPI's own code is relatively thin — 23 files, ~522K characters in the `fastapi/` package — because it delegates transport to Starlette and validation to Pydantic, focusing its value on the declarative API surface that ties them together.

### 1.1 High-level component diagram

```text
+---------------------------------------------------------------+
|  APPLICATION CODE                                              |
|  @app.get("/items/{id}")                                       |
|  async def read_item(id: int, q: str = Query(...)): ...        |
+----------------------------+----------------------------------+
                             |
                             v
+---------------------------------------------------------------+
|  FastAPI  (applications.py)                                    |
|    extends Starlette                                           |
|    - APIRouter tree (routing.py)                               |
|    - Dependency injection (dependencies/)                      |
|    - Parameter resolution (params.py, param_functions.py)      |
|    - OpenAPI schema generation (openapi/)                      |
|    - Security utilities (security/)                            |
+----------------------------+----------------------------------+
                             |
                             v
+---------------------------------------------------------------+
|  Starlette  (ASGI framework)                                   |
|    - Routing, Request/Response, WebSocket                      |
|    - Middleware stack                                           |
|    - Static files, background tasks                            |
|    - TestClient (httpx-based)                                  |
+----------------------------+----------------------------------+
                             |
                             v
+---------------------------------------------------------------+
|  Pydantic v2                                                   |
|    - Model validation, JSON Schema generation                  |
|    - Field metadata (used by FastAPI params)                    |
|    - BaseSettings for configuration                            |
+----------------------------+----------------------------------+
                             |
                             v
+---------------------------------------------------------------+
|  ASGI Server                                                   |
|    Uvicorn / Hypercorn / Daphne / Gunicorn w/ UvicornWorker    |
+---------------------------------------------------------------+
```

### 1.2 The middleware stack

When `FastAPI.build_middleware_stack()` executes (inherited from Starlette, called lazily on first request), it constructs the following chain:

```text
Incoming ASGI request
  |
  v
ServerErrorMiddleware          # Catches unhandled exceptions, returns 500
  |
  v
User-registered middleware     # app.add_middleware(...) in LIFO order
  |
  v
ExceptionMiddleware            # Routes exceptions to registered handlers
  |
  v
AsyncExitStackMiddleware       # FastAPI's own — manages dependency exit stacks
  |
  v
Router                         # Starlette route matching + endpoint dispatch
```

> [!IMPORTANT]
> The `AsyncExitStackMiddleware` is FastAPI-specific (defined in `fastapi/middleware/asyncexitstack.py`). It creates an `AsyncExitStack` on `request.state` that dependency injection uses to manage generator-based dependencies (those using `yield`). Without this middleware, dependencies that yield would never have their cleanup code executed.

### 1.3 Component inventory

| Component | Source path | Role |
|---|---|---|
| **FastAPI app** | `fastapi/applications.py` | Main application class; extends `Starlette`; holds routers, OpenAPI config, exception handlers, lifespan. |
| **APIRouter** | `fastapi/routing.py` | Route registration, path operation decoration, sub-router inclusion. |
| **APIRoute / APIWebSocketRoute** | `fastapi/routing.py` | Individual route wrappers; compile endpoint functions into ASGI apps with dependency resolution. |
| **Parameter classes** | `fastapi/params.py` | `Path`, `Query`, `Header`, `Cookie`, `Body`, `Form`, `File`, `Depends`, `Security` — extend Pydantic `FieldInfo`. |
| **Parameter functions** | `fastapi/param_functions.py` | Function-form wrappers around parameter classes for cleaner syntax. |
| **OpenAPI generation** | `fastapi/openapi/utils.py` | `get_openapi()` — builds the complete OpenAPI 3.1.0 JSON schema from registered routes. |
| **OpenAPI models** | `fastapi/openapi/models.py` | Full Pydantic model tree for OpenAPI 3.1.0 spec objects. |
| **Interactive docs** | `fastapi/openapi/docs.py` | HTML generators for Swagger UI and ReDoc. |
| **Security schemes** | `fastapi/security/` | OAuth2, HTTP Basic/Bearer/Digest, API key, OpenID Connect dependency providers. |
| **Encoders** | `fastapi/encoders.py` | `jsonable_encoder()` — recursive Pydantic model to JSON-safe dict conversion. |
| **SSE support** | `fastapi/sse.py` | `EventSourceResponse`, `ServerSentEvent` for server-sent event streaming. |
| **Exception types** | `fastapi/exceptions.py` | `HTTPException`, `WebSocketException`, `RequestValidationError`, `ResponseValidationError`. |
| **Exception handlers** | `fastapi/exception_handlers.py` | Default handlers wired at app startup. |
| **Middleware re-exports** | `fastapi/middleware/` | CORS, GZip, HTTPS redirect, trusted host, WSGI — all re-exported from Starlette. |
| **Compatibility layer** | `fastapi/_compat/` | Pydantic v2 adaptation: `ModelField`, `GenerateJsonSchema`, field serialization. |
| **Responses** | `fastapi/responses.py` | `UJSONResponse`, `ORJSONResponse` for alternative JSON serializers. |
| **Data structures** | `fastapi/datastructures.py` | `UploadFile` (extends Starlette), `DefaultPlaceholder`, `Default`. |
| **Background tasks** | `fastapi/background.py` | `BackgroundTasks` re-export from Starlette. |
| **CLI delegation** | `fastapi/cli.py` | Defers to `fastapi-cli` package; raises `RuntimeError` if not installed. |
| **Re-exports** | `fastapi/requests.py`, `fastapi/websockets.py` | `Request`, `WebSocket` from Starlette. |
| **Utilities** | `fastapi/utils.py`, `fastapi/types.py`, `fastapi/logger.py` | Internal helpers, type aliases, configured logger. |

### 1.4 Technology stack

| Layer | Library | Role |
|---|---|---|
| ASGI framework | Starlette | HTTP/WebSocket protocol, routing, middleware, test client |
| Data validation | Pydantic v2 | Request/response validation, JSON Schema, settings |
| ASGI server | Uvicorn (recommended) | Production-grade ASGI server with uvloop |
| Form parsing | python-multipart | Required for `Form()` and `File()` parameters |
| Async test client | httpx | Powers `TestClient` and async testing |
| Optional JSON | orjson, ujson | Alternative JSON serializers for `ORJSONResponse`, `UJSONResponse` |
| Optional JWT | python-jose, PyJWT | JWT encoding/decoding in security examples |
| Optional hashing | passlib, bcrypt | Password hashing in security examples |
| Optional ORM | SQLModel | SQL database integration (SQLAlchemy + Pydantic) |
| Optional SSE | sse-starlette (or built-in) | Server-sent events (FastAPI now has built-in `sse.py`) |

> [!NOTE]
> FastAPI's core package has minimal hard dependencies: `starlette`, `pydantic`, and `typing-extensions`. Everything else — `python-multipart`, `orjson`, `ujson`, `python-jose`, `passlib`, `sqlmodel`, `httpx` — is optional and only needed when you use the corresponding features. The `python-multipart` dependency is required at runtime only if you declare `Form()`, `File()`, or `UploadFile` parameters.

---

## 2. System Requirements

### 2.1 Runtime requirements

| Requirement | Minimum | Recommended |
|---|---|---|
| Python | 3.8+ | 3.11+ (for performance and typing improvements) |
| Starlette | Compatible version pinned by FastAPI | Latest compatible |
| Pydantic | v2.0+ | v2.7+ (latest v2 line) |
| ASGI server | Any ASGI 3.0 server | Uvicorn 0.25+ with `uvloop` and `httptools` |
| OS | Linux, macOS, Windows | Linux (for production deployments) |

### 2.2 Installation matrix

```bash
# Minimal install
pip install fastapi

# With ASGI server (required for running)
pip install "fastapi[standard]"
# Includes: uvicorn, httpx, python-multipart, email-validator, jinja2

# Individual extras
pip install uvicorn[standard]    # uvloop + httptools + watchfiles
pip install python-multipart     # Form/File support
pip install orjson               # ORJSONResponse
pip install ujson                # UJSONResponse
pip install python-jose[cryptography]  # JWT tokens
pip install passlib[bcrypt]      # Password hashing
pip install sqlmodel             # Database ORM
pip install httpx                # Async HTTP + TestClient
pip install pydantic-settings    # BaseSettings for config
```

### 2.3 Hardware sizing guidelines

| Deployment size | vCPUs | RAM | Workers | Expected RPS |
|---|---|---|---|---|
| Development | 1 | 512 MB | 1 (auto-reload) | N/A |
| Small (< 100 concurrent) | 2 | 1 GB | 2-4 | 1,000-5,000 |
| Medium (100-1,000 concurrent) | 4 | 4 GB | 4-8 | 5,000-20,000 |
| Large (1,000+ concurrent) | 8+ | 8+ GB | 8-16 | 20,000-100,000+ |

> [!TIP]
> Worker count formula: `(2 * CPU_CORES) + 1` for CPU-bound workloads. For I/O-bound async endpoints (the common case with FastAPI), a single worker with async handlers can saturate a CPU core. Scale workers to match CPU cores, not connections.

---

## 3. Configuration Reference

FastAPI applications are configured through the `FastAPI()` constructor, ASGI server settings, and application-level patterns (environment variables via `pydantic-settings`). There is no configuration file format built into FastAPI itself.

### 3.1 Complete `FastAPI()` constructor parameters

Every parameter accepted by `FastAPI.__init__()` as found in `applications.py`:

| Parameter | Type | Default | Description |
|---|---|---|---|
| `debug` | `bool` | `False` | Enables Starlette debug mode; shows tracebacks in 500 responses. **Never enable in production.** |
| `title` | `str` | `"FastAPI"` | API title shown in OpenAPI schema and interactive docs. |
| `summary` | `str \| None` | `None` | Short API summary for OpenAPI `info.summary`. |
| `description` | `str` | `""` | API description (Markdown supported) for OpenAPI `info.description`. |
| `version` | `str` | `"0.1.0"` | API version string for OpenAPI `info.version`. |
| `openapi_url` | `str \| None` | `"/openapi.json"` | Path where the OpenAPI JSON schema is served. Set to `None` to disable OpenAPI entirely. |
| `openapi_tags` | `list[dict] \| None` | `None` | Tag metadata for OpenAPI schema grouping. |
| `servers` | `list[dict] \| None` | `None` | Server objects for the OpenAPI `servers` array. |
| `dependencies` | `Sequence[Depends] \| None` | `None` | Global dependencies applied to every route. |
| `default_response_class` | `type[Response]` | `JSONResponse` | Default response class for all routes. Change to `ORJSONResponse` or `UJSONResponse` for faster JSON serialization. |
| `redirect_slashes` | `bool` | `True` | Whether to redirect `/path` to `/path/` (or vice versa) when a route match is found for the alternate form. |
| `docs_url` | `str \| None` | `"/docs"` | Path for Swagger UI. Set to `None` to disable. |
| `redoc_url` | `str \| None` | `"/redoc"` | Path for ReDoc. Set to `None` to disable. |
| `swagger_ui_oauth2_redirect_url` | `str \| None` | `"/docs/oauth2-redirect"` | OAuth2 redirect URL for Swagger UI authorization flow. |
| `swagger_ui_init_oauth` | `dict \| None` | `None` | Initial OAuth2 configuration for Swagger UI (passed to `ui.initOAuth()`). |
| `middleware` | `Sequence[Middleware] \| None` | `None` | Middleware to register at construction time (alternative to `app.add_middleware()`). |
| `exception_handlers` | `dict \| None` | `None` | Exception-to-handler mapping registered at construction time. |
| `on_startup` | `Sequence[Callable] \| None` | `None` | **Deprecated.** Startup event handlers. Use `lifespan` instead. |
| `on_shutdown` | `Sequence[Callable] \| None` | `None` | **Deprecated.** Shutdown event handlers. Use `lifespan` instead. |
| `lifespan` | `Lifespan \| None` | `None` | Async context manager for application lifespan (startup/shutdown). Replaces `on_startup`/`on_shutdown`. |
| `terms_of_service` | `str \| None` | `None` | URL to terms of service for OpenAPI `info.termsOfService`. |
| `contact` | `dict \| None` | `None` | Contact info for OpenAPI `info.contact`. |
| `license_info` | `dict \| None` | `None` | License info for OpenAPI `info.license`. |
| `root_path` | `str` | `""` | ASGI root path (for reverse proxy path prefixing). Equivalent to Uvicorn's `--root-path`. |
| `root_path_in_servers` | `bool` | `True` | Whether to include `root_path` as the first entry in OpenAPI `servers`. |
| `responses` | `dict \| None` | `None` | Additional global responses for all routes (merged into OpenAPI schema). |
| `callbacks` | `list[BaseRoute] \| None` | `None` | Global OpenAPI callback routes. |
| `webhooks` | `APIRouter \| None` | `None` | Webhook definitions for OpenAPI 3.1.0. |
| `deprecated` | `bool \| None` | `None` | Mark all routes as deprecated in OpenAPI schema. |
| `include_in_schema` | `bool` | `True` | Whether to include routes in the OpenAPI schema. |
| `swagger_ui_parameters` | `dict \| None` | `None` | Custom parameters passed to Swagger UI initialization (e.g., `{"persistAuthorization": True}`). |
| `generate_unique_id_function` | `Callable` | `Default(generate_unique_id)` | Function to generate unique operation IDs for OpenAPI. Default: `{method}_{path}__{name}`. |
| `separate_input_output_schemas` | `bool` | `True` | When `True`, generates separate schemas for request/response models (input uses `mode='validation'`, output uses `mode='serialization'`). |
| `openapi_external_docs` | `dict \| None` | `None` | External docs link for OpenAPI `externalDocs`. |
| `strict_content_type` | `bool` | `True` | When `True`, strictly validates request Content-Type headers against expected media types. |

> [!WARNING]
> Setting `openapi_url` to `None` disables the OpenAPI schema endpoint entirely, which also disables `/docs` and `/redoc`. This is recommended for production APIs that should not expose their schema publicly. The interactive docs are a development tool, not a production feature.

### 3.2 Route decorator parameters

Parameters accepted by `@app.get()`, `@app.post()`, and other HTTP method decorators (defined in `APIRouter.api_route()`):

| Parameter | Type | Default | Description |
|---|---|---|---|
| `path` | `str` | (required) | URL path (supports `{param}` path parameters). |
| `response_model` | `type \| None` | `None` | Pydantic model for response validation/serialization. |
| `status_code` | `int \| None` | `None` | Default HTTP status code (e.g., `201` for POST). |
| `tags` | `list[str \| Enum]` | `None` | OpenAPI tags for grouping. |
| `dependencies` | `Sequence[Depends]` | `None` | Route-level dependencies (in addition to router/app-level). |
| `summary` | `str` | `None` | OpenAPI operation summary. |
| `description` | `str` | `None` | OpenAPI operation description. |
| `response_description` | `str` | `"Successful Response"` | OpenAPI response description. |
| `responses` | `dict` | `None` | Additional response schemas for OpenAPI. |
| `deprecated` | `bool` | `None` | Mark route as deprecated in OpenAPI. |
| `operation_id` | `str` | `None` | Custom OpenAPI operation ID. |
| `response_model_include` | `set` | `None` | Fields to include in response model. |
| `response_model_exclude` | `set` | `None` | Fields to exclude from response model. |
| `response_model_by_alias` | `bool` | `True` | Use model field aliases in response. |
| `response_model_exclude_unset` | `bool` | `False` | Exclude unset fields from response. |
| `response_model_exclude_defaults` | `bool` | `False` | Exclude default-valued fields. |
| `response_model_exclude_none` | `bool` | `False` | Exclude `None`-valued fields. |
| `include_in_schema` | `bool` | `True` | Whether to include in OpenAPI schema. |
| `response_class` | `type[Response]` | `Default(JSONResponse)` | Response class for this route. |
| `name` | `str` | `None` | Route name (used in URL generation). |
| `callbacks` | `list[BaseRoute]` | `None` | OpenAPI callback routes. |
| `openapi_extra` | `dict` | `None` | Extra OpenAPI schema data merged into the operation. |
| `generate_unique_id_function` | `Callable` | `Default(generate_unique_id)` | Per-route unique ID generator override. |

### 3.3 Application settings pattern (pydantic-settings)

FastAPI does not have a built-in configuration file format. The canonical pattern for application configuration uses `pydantic-settings`:

```python
from functools import lru_cache
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "My API"
    admin_email: str = "[email removed]"
    database_url: str = "sqlite:///./app.db"
    secret_key: str = "change-me"
    debug: bool = False
    items_per_page: int = 50
    allowed_hosts: list[str] = ["*"]

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
    )

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

> [!TIP]
> The `@lru_cache` decorator on `get_settings()` ensures the settings object is created once and reused. This is critical for performance — without it, `Settings()` would read environment variables and parse the `.env` file on every request that depends on settings. For testing, use `app.dependency_overrides[get_settings] = lambda: TestSettings()`.

### 3.4 ASGI server configuration (Uvicorn)

Key Uvicorn settings that affect FastAPI behavior:

| Setting | CLI flag | Default | Description |
|---|---|---|---|
| Host | `--host` | `127.0.0.1` | Bind address. Use `0.0.0.0` for container/production deployments. |
| Port | `--port` | `8000` | Bind port. |
| Workers | `--workers` | `1` | Number of worker processes (use for multi-core). |
| Root path | `--root-path` | `""` | ASGI root path for reverse proxy setups. |
| Reload | `--reload` | `False` | Auto-reload on code changes. **Development only.** |
| Loop | `--loop` | `auto` | Event loop: `auto`, `asyncio`, `uvloop`. `uvloop` recommended for production. |
| HTTP parser | `--http` | `auto` | HTTP parser: `auto`, `h11`, `httptools`. `httptools` is faster. |
| Log level | `--log-level` | `info` | Logging level: `critical`, `error`, `warning`, `info`, `debug`, `trace`. |
| Access log | `--access-log` / `--no-access-log` | enabled | Disable for maximum throughput. |
| Limit concurrency | `--limit-concurrency` | `None` | Max concurrent connections before returning 503. |
| Limit max requests | `--limit-max-requests` | `None` | Worker recycling: restart after N requests (guards against memory leaks). |
| Timeout keep-alive | `--timeout-keep-alive` | `5` | Keep-alive timeout in seconds. |
| SSL cert | `--ssl-certfile` | `None` | TLS certificate file (usually handled by reverse proxy). |
| SSL key | `--ssl-keyfile` | `None` | TLS key file. |
| Proxy headers | `--proxy-headers` | `True` | Trust `X-Forwarded-*` headers from reverse proxy. |
| Forwarded allow IPs | `--forwarded-allow-ips` | `127.0.0.1` | IPs trusted for proxy headers. |

---

## 4. Deployment and Scaling

### 4.1 Production deployment topologies

#### Single-server deployment

```text
                    Internet
                       |
              +--------v--------+
              |  Reverse proxy  |
              |  nginx / Caddy  |
              |  (TLS, static)  |
              +--------+--------+
                       |
              +--------v--------+
              |  Gunicorn        |
              |  w/ UvicornWorker|
              |  (N workers)     |
              +--------+--------+
                       |
              +--------v--------+
              |  FastAPI app     |
              |  (per worker)    |
              +-----------------+
```

```bash
# Production command with Gunicorn
gunicorn app.main:app \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --timeout 120 \
    --graceful-timeout 30 \
    --max-requests 10000 \
    --max-requests-jitter 1000 \
    --access-logfile - \
    --error-logfile -
```

#### Container deployment

```dockerfile
FROM python:3.12-slim

WORKDIR /app

# Install dependencies first (layer caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY ./app ./app

# Non-root user
RUN adduser --disabled-password --no-create-home appuser
USER appuser

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
```

> [!CAUTION]
> Do **not** use `--reload` in production containers. The file-watcher consumes CPU, and the auto-reload behavior creates unpredictable restart windows. Always use multi-worker mode (`--workers`) or Gunicorn with `UvicornWorker` for production.

#### Kubernetes deployment

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: fastapi-app
  template:
    metadata:
      labels:
        app: fastapi-app
    spec:
      containers:
      - name: api
        image: myregistry/fastapi-app:latest
        ports:
        - containerPort: 8000
        resources:
          requests:
            cpu: "500m"
            memory: "256Mi"
          limits:
            cpu: "1000m"
            memory: "512Mi"
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 10
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 10
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database-url
```

### 4.2 Reverse proxy configuration

#### Nginx

```nginx
upstream fastapi_backend {
    server 127.0.0.1:8000;
    # Add more servers for load balancing
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;

    # WebSocket support
    location /ws {
        proxy_pass http://fastapi_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
    }

    # SSE support (disable buffering)
    location /stream {
        proxy_pass http://fastapi_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_cache off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Standard API
    location / {
        proxy_pass http://fastapi_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

> [!IMPORTANT]
> When deploying behind a reverse proxy, you **must** either pass `--root-path /api/v1` to Uvicorn or set `root_path="/api/v1"` in the `FastAPI()` constructor if the proxy strips or rewrites the path prefix. Without this, the OpenAPI schema will generate incorrect URLs for the interactive docs. The `root_path_in_servers=True` default ensures the root path appears in the OpenAPI `servers` array.

### 4.3 Scaling strategies

| Strategy | When to use | How |
|---|---|---|
| **Vertical (more workers)** | Single-server, CPU-bound endpoints | Increase `--workers` in Uvicorn/Gunicorn. Formula: `2 * cores + 1`. |
| **Horizontal (more instances)** | Multi-server, stateless API | Deploy multiple containers behind a load balancer. Ensure session state is external (Redis, DB). |
| **Async I/O** | I/O-bound endpoints (DB, HTTP calls) | Use `async def` endpoints with async database drivers (`asyncpg`, `aiosqlite`). A single worker handles thousands of concurrent I/O-bound requests. |
| **Background tasks** | Long-running operations | Use `BackgroundTasks` for simple fire-and-forget, or Celery/ARQ for distributed task queues. |
| **Caching** | Read-heavy endpoints | Add Redis/Memcached caching at the application or reverse proxy layer. |
| **CDN/Edge** | Static responses, geographic distribution | Place a CDN (CloudFlare, CloudFront) in front for cacheable responses. |

---

## 5. Operations

### 5.1 Health checks

FastAPI does not ship a built-in health endpoint. The standard pattern:

```python
from fastapi import FastAPI, status

app = FastAPI()

@app.get("/health", status_code=status.HTTP_200_OK)
async def health_check():
    return {"status": "healthy"}

@app.get("/health/ready", status_code=status.HTTP_200_OK)
async def readiness_check():
    """Check downstream dependencies."""
    # Check database connectivity
    try:
        await db.execute("SELECT 1")
    except Exception:
        return JSONResponse(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            content={"status": "unhealthy", "detail": "database unreachable"}
        )
    return {"status": "ready"}
```

### 5.2 Logging

FastAPI uses Python's standard `logging` module. The framework logger is configured in `fastapi/logger.py`:

```python
import logging
logger = logging.getLogger("fastapi")
```

Production logging configuration:

```python
import logging
import sys

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
    handlers=[logging.StreamHandler(sys.stdout)],
)

# Suppress noisy libraries
logging.getLogger("uvicorn.access").setLevel(logging.WARNING)
logging.getLogger("uvicorn.error").setLevel(logging.INFO)
```

For structured logging (JSON), use `python-json-logger` or `structlog`:

```python
import structlog

structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer(),
    ],
    logger_factory=structlog.stdlib.LoggerFactory(),
)
```

### 5.3 Lifespan management

The `lifespan` parameter replaces the deprecated `on_startup`/`on_shutdown` events:

```python
from contextlib import asynccontextmanager
from fastapi import FastAPI

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup: runs before accepting requests
    db_pool = await create_db_pool()
    app.state.db_pool = db_pool
    ml_model = load_model()
    app.state.ml_model = ml_model

    yield  # Application runs here

    # Shutdown: runs after last request completes
    await db_pool.close()

app = FastAPI(lifespan=lifespan)
```

> [!NOTE]
> The `lifespan` context manager receives the `FastAPI` app instance as its argument. Resources initialized during startup should be stored on `app.state` and accessed from dependencies or endpoints. The `yield` statement marks the boundary between startup and shutdown. If startup raises an exception, the application does not start and shutdown code does not run.

### 5.4 Graceful shutdown

Uvicorn handles `SIGTERM` and `SIGINT` by default:

1. Stop accepting new connections
2. Wait for in-flight requests to complete (up to `--timeout-graceful-shutdown`, default 0 = wait forever)
3. Run lifespan shutdown
4. Exit

For Gunicorn with UvicornWorker:

```bash
# Graceful restart (reload workers one at a time)
kill -HUP $(cat /var/run/gunicorn.pid)

# Graceful shutdown
kill -TERM $(cat /var/run/gunicorn.pid)
```

### 5.5 Monitoring and observability

#### Prometheus metrics

```python
from prometheus_client import Counter, Histogram, generate_latest
from starlette.middleware.base import BaseHTTPMiddleware
import time

REQUEST_COUNT = Counter(
    "http_requests_total",
    "Total HTTP requests",
    ["method", "endpoint", "status"]
)
REQUEST_LATENCY = Histogram(
    "http_request_duration_seconds",
    "Request latency",
    ["method", "endpoint"]
)

class PrometheusMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        start = time.perf_counter()
        response = await call_next(request)
        duration = time.perf_counter() - start
        REQUEST_COUNT.labels(
            method=request.method,
            endpoint=request.url.path,
            status=response.status_code
        ).inc()
        REQUEST_LATENCY.labels(
            method=request.method,
            endpoint=request.url.path
        ).observe(duration)
        return response

app.add_middleware(PrometheusMiddleware)

@app.get("/metrics")
async def metrics():
    return Response(
        content=generate_latest(),
        media_type="text/plain; version=0.0.4"
    )
```

#### OpenTelemetry integration

```python
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint="http://collector:4317"))
)

FastAPIInstrumentor.instrument_app(app)
```

---

## 6. Performance

### 6.1 Async vs sync endpoints

FastAPI handles `async def` and `def` endpoints differently:

| Endpoint type | Execution model | Best for |
|---|---|---|
| `async def` | Runs directly on the event loop | I/O-bound work: database queries, HTTP calls, file I/O (with async drivers) |
| `def` (sync) | Runs in a thread pool (`anyio.to_thread.run_sync`) | CPU-bound work, blocking I/O, legacy sync code |

> [!WARNING]
> Using blocking I/O (e.g., `requests.get()`, `time.sleep()`, sync database drivers) inside an `async def` endpoint **blocks the entire event loop**, preventing all other requests from being processed. Either use `def` (sync) endpoints so FastAPI runs them in a thread pool, or use async-native libraries (`httpx`, `asyncpg`, `aiofiles`).

### 6.2 JSON serialization performance

| Serializer | Response class | Relative speed | Notes |
|---|---|---|---|
| `json` (stdlib) | `JSONResponse` (default) | 1x (baseline) | Universal compatibility |
| `orjson` | `ORJSONResponse` | ~3-10x faster | Binary output, handles `datetime`/`numpy` natively; `pip install orjson` |
| `ujson` | `UJSONResponse` | ~2-4x faster | `pip install ujson` |

To use globally:

```python
from fastapi.responses import ORJSONResponse

app = FastAPI(default_response_class=ORJSONResponse)
```

### 6.3 Response model optimization

```python
# SLOW: validates and serializes the full model every time
@app.get("/items/", response_model=list[Item])
async def list_items():
    return await db.fetch_all_items()

# FASTER: exclude fields you don't need
@app.get("/items/", response_model=list[Item], response_model_exclude={"internal_field"})
async def list_items():
    return await db.fetch_all_items()

# FASTEST: return Response directly (no validation overhead)
@app.get("/items/")
async def list_items():
    items = await db.fetch_all_items()
    return ORJSONResponse(content=[item.model_dump() for item in items])
```

### 6.4 Dependency injection caching

Dependencies with the same parameters in the same request are resolved once and cached:

```python
async def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# Both parameters resolve to the SAME db session within one request
@app.get("/items/{id}")
async def get_item(id: int, db: Session = Depends(get_db)):
    ...
```

To force re-evaluation, use `Depends(get_db, use_cache=False)`.

### 6.5 OpenAPI schema generation

The OpenAPI schema is generated lazily on first access to `openapi_url` and then cached on `app.openapi_schema`. For applications with hundreds of routes, initial schema generation can take noticeable time. The schema is regenerated only if `app.openapi_schema` is set to `None`.

To pre-generate and cache at startup:

```python
@asynccontextmanager
async def lifespan(app: FastAPI):
    app.openapi()  # Force schema generation at startup
    yield
```

### 6.6 Connection pooling

FastAPI itself does not manage database connections. Common patterns:

```python
# SQLAlchemy async with connection pool
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession

engine = create_async_engine(
    "postgresql+asyncpg://user:pass@host/db",
    pool_size=20,          # Concurrent connections
    max_overflow=10,       # Extra connections under load
    pool_pre_ping=True,    # Validate connections before use
    pool_recycle=3600,     # Recycle connections after 1 hour
)
```

---

## 7. Security

### 7.1 Security scheme architecture

FastAPI's security module (`fastapi/security/`) provides dependency-injectable security schemes that integrate with OpenAPI. These are **not authentication implementations** — they are protocol extractors that parse credentials from requests and declare security requirements in the OpenAPI schema.

| Class | Module | What it extracts | OpenAPI scheme |
|---|---|---|---|
| `OAuth2PasswordBearer` | `oauth2.py` | Bearer token from `Authorization` header | `oauth2` with `password` flow |
| `OAuth2AuthorizationCodeBearer` | `oauth2.py` | Bearer token from `Authorization` header | `oauth2` with `authorizationCode` flow |
| `OAuth2PasswordRequestForm` | `oauth2.py` | Form fields: `username`, `password`, `scope`, `grant_type`, `client_id`, `client_secret` | N/A (form parser) |
| `SecurityScopes` | `oauth2.py` | Aggregated scopes from the dependency chain | N/A (scope aggregator) |
| `HTTPBasic` | `http.py` | Username/password from `Authorization: Basic` header | `http` with `basic` scheme |
| `HTTPBearer` | `http.py` | Token from `Authorization: Bearer` header | `http` with `bearer` scheme |
| `HTTPDigest` | `http.py` | Credentials from `Authorization: Digest` header | `http` with `digest` scheme |
| `APIKeyQuery` | `api_key.py` | API key from query parameter | `apiKey` in `query` |
| `APIKeyHeader` | `api_key.py` | API key from custom header | `apiKey` in `header` |
| `APIKeyCookie` | `api_key.py` | API key from cookie | `apiKey` in `cookie` |
| `OpenIdConnect` | `open_id_connect_url.py` | Token from `Authorization` header | `openIdConnect` |

All security classes inherit from `SecurityBase` (`security/base.py`) which stores the OpenAPI security scheme model.

### 7.2 Authentication patterns

#### JWT Bearer Token (the canonical pattern from docs_src)

```python
from datetime import datetime, timedelta
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel

SECRET_KEY = "your-secret-key"  # Use a proper secret
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

class TokenData(BaseModel):
    username: str | None = None
    scopes: list[str] = []

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_scopes = payload.get("scopes", [])
        token_data = TokenData(username=username, scopes=token_scopes)
    except JWTError:
        raise credentials_exception
    user = get_user(db, username=token_data.username)
    if user is None:
        raise credentials_exception
    return user
```

### 7.3 CORS configuration

```python
from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://app.example.com"],  # NEVER use ["*"] in production
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
    expose_headers=["X-Request-ID"],
    max_age=600,  # Preflight cache in seconds
)
```

> [!CAUTION]
> Setting `allow_origins=["*"]` with `allow_credentials=True` is a security misconfiguration. The CORS spec requires that when credentials are allowed, origins must be explicitly listed. Starlette's `CORSMiddleware` will silently downgrade `allow_credentials` to `False` when `allow_origins=["*"]` is used, which may break authenticated cross-origin requests without any error message.

### 7.4 Request validation security

FastAPI's type-driven validation provides defense-in-depth against injection attacks:

| Attack vector | FastAPI mitigation |
|---|---|
| **SQL injection** | Path/query parameters are type-validated (e.g., `id: int` rejects strings); use parameterized queries in the data layer. |
| **XSS** | JSON responses are Content-Type `application/json` by default; HTML must be explicitly returned. |
| **Path traversal** | Path parameters are validated against the path template; no filesystem path interpretation. |
| **Request smuggling** | Handled by the ASGI server (Uvicorn/Hypercorn), not FastAPI. |
| **Oversized payloads** | Configure `--limit-max-request-size` in Uvicorn (default: unlimited). |
| **Slowloris** | Configure `--timeout-keep-alive` in Uvicorn and use a reverse proxy with request timeouts. |

### 7.5 Validation error handling

When request validation fails, FastAPI raises `RequestValidationError` (which extends Pydantic's `ValidationError`). The default handler returns a 422 response with detailed error information:

```json
{
    "detail": [
        {
            "type": "missing",
            "loc": ["body", "name"],
            "msg": "Field required",
            "input": {},
            "url": "https://errors.pydantic.dev/2/v/missing"
        }
    ]
}
```

> [!WARNING]
> The default 422 response can leak internal field names and model structure to clients. In production, consider overriding the validation error handler to return sanitized error messages:
> ```python
> from fastapi.exceptions import RequestValidationError
>
> @app.exception_handler(RequestValidationError)
> async def validation_exception_handler(request, exc):
>     return JSONResponse(
>         status_code=422,
>         content={"detail": "Invalid request parameters"},
>     )
> ```

### 7.6 Trusted host middleware

```python
from fastapi.middleware.trustedhost import TrustedHostMiddleware

app.add_middleware(
    TrustedHostMiddleware,
    allowed_hosts=["api.example.com", "*.example.com"],
)
```

This rejects requests with `Host` headers that do not match the allowed list, preventing host header injection attacks.

### 7.7 HTTPS redirect

```python
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

app.add_middleware(HTTPSRedirectMiddleware)
```

Forces all HTTP requests to redirect to HTTPS. Only enable when TLS termination is properly configured.

### 7.8 Secret management

FastAPI does not include secret management. Best practices:

| Environment | Approach |
|---|---|
| Development | `.env` file with `pydantic-settings` |
| Containers | Environment variables via orchestrator secrets |
| Kubernetes | `Secret` resources mounted as env vars |
| AWS | AWS Secrets Manager or SSM Parameter Store |
| GCP | Google Secret Manager |
| Azure | Azure Key Vault |

---

## 8. Developer Internals

### 8.1 Request processing pipeline

When a request arrives at a FastAPI endpoint, the following sequence executes:

```text
1. ASGI server receives HTTP request
2. ServerErrorMiddleware wraps the call
3. User middleware chain executes (request phase)
4. ExceptionMiddleware wraps the call
5. AsyncExitStackMiddleware creates request.state._exit_stack
6. Router matches the path to an APIRoute
7. APIRoute.get_route_handler() returns the endpoint wrapper
8. Dependency resolution begins:
   a. Build dependency graph from function signature
   b. Resolve dependencies depth-first (respecting cache)
   c. For generator dependencies (yield), enter the context
9. Parameter extraction:
   a. Path parameters extracted from URL and validated
   b. Query parameters extracted and validated
   c. Header parameters extracted and validated
   d. Cookie parameters extracted and validated
   e. Body parsed (JSON, form, multipart) and validated
10. Endpoint function called with resolved parameters
11. Response model validation (if response_model specified)
12. Response serialized (jsonable_encoder → response class)
13. Generator dependencies exit (cleanup after yield)
14. AsyncExitStack closes
15. User middleware chain executes (response phase)
16. Response sent to client
```

### 8.2 Dependency injection internals

The dependency injection system is implemented across `fastapi/dependencies/` and integrated into `fastapi/routing.py`. Key mechanics:

#### Dependency graph resolution

Dependencies are resolved recursively. Each `Depends()` parameter creates a node in a directed acyclic graph. The resolver:

1. Inspects the endpoint function signature using `inspect.signature()`
2. For each parameter with a `Depends` default, recursively resolves the dependency's own parameters
3. Builds a flat execution plan (topological sort)
4. Executes dependencies bottom-up, caching results per request

#### Generator dependencies (yield-based)

```python
async def get_db():
    db = SessionLocal()
    try:
        yield db     # <-- dependency value injected here
    finally:
        db.close()   # <-- runs after the response is sent
```

The `AsyncExitStackMiddleware` creates an `AsyncExitStack` per request. Generator dependencies are entered into this stack via `contextmanager` / `asynccontextmanager` wrappers. The exit stack unwinds after the response is sent, executing `finally` blocks.

> [!IMPORTANT]
> There is a known edge case in `routing.py` (line ~125): if a dependency with `yield` uses a bare `except:` clause (catching `BaseException`), it can intercept `GeneratorExit` and `CancelledError`, leading to the error `FastAPIError: "Response not awaited"`. Always use `except Exception:` in yield dependencies, never bare `except:`.

#### Dependency scoping

| Scope | Behavior | Example |
|---|---|---|
| **Request-scoped** (default) | One instance per request, cached within that request | Database sessions |
| **Uncached** | New instance on every injection point | `Depends(dep, use_cache=False)` |
| **Application-scoped** | Share state across requests | Use `@lru_cache` or store on `app.state` |

### 8.3 OpenAPI schema generation internals

The schema generation pipeline (`fastapi/openapi/utils.py`):

1. `get_openapi()` is called with the app's routes and metadata
2. For each `APIRoute`, extract:
   - Path and HTTP methods
   - Request body schema (from Pydantic models in `Body` params)
   - Query/path/header/cookie parameter schemas
   - Response model schema
   - Security requirements from `Security()` dependencies
3. Pydantic models are converted to JSON Schema via `model.model_json_schema()`
4. When `separate_input_output_schemas=True` (default), input schemas use `mode='validation'` and output schemas use `mode='serialization'` — this means models with computed fields, aliases, or default factories may have different input/output representations
5. Schemas are deduplicated and placed in `components.schemas`
6. The complete OpenAPI 3.1.0 document is returned as a dict

The OpenAPI models in `fastapi/openapi/models.py` define the full OpenAPI 3.1.0 specification as Pydantic models:

| Model | OpenAPI Object |
|---|---|
| `OpenAPI` | Root document |
| `Info` | API metadata |
| `PathItem` | Path operations |
| `Operation` | Single operation |
| `Parameter` | Query/path/header/cookie params |
| `RequestBody` | Request body |
| `MediaType` | Content type definitions |
| `Schema` | JSON Schema (extended) |
| `SecurityScheme` | Auth scheme definitions |
| `Components` | Reusable components |
| `Tag` | Tag metadata |
| `Server` | Server definitions |
| `ExternalDocumentation` | External docs link |
| `Webhook` | Webhook definitions |

### 8.4 Pydantic v2 compatibility layer

The `fastapi/_compat/` package bridges FastAPI's internal needs with Pydantic v2's API:

- **`ModelField`** — FastAPI's internal representation of a route parameter. Wraps Pydantic's `FieldInfo` with additional metadata (field location, alias, required status, validators).
- **`GenerateJsonSchema`** — Custom JSON Schema generator that handles FastAPI-specific schema modifications (e.g., `UploadFile` represented as `{"type": "string", "format": "binary"}`).
- **Validation adapters** — Functions that bridge between FastAPI's parameter extraction and Pydantic v2's `TypeAdapter` for validation.

> [!NOTE]
> FastAPI dropped Pydantic v1 support. The `PydanticV1NotSupportedError` in `encoders.py` and `utils.py` is raised if a `pydantic.v1` model is detected as a response model or passed to `jsonable_encoder()`. The error message explicitly states that Pydantic v1 compatibility models are no longer supported.

### 8.5 The `jsonable_encoder()` function

`fastapi/encoders.py` provides `jsonable_encoder()`, which recursively converts Python objects into JSON-serializable types:

```text
Input types handled:
  Pydantic BaseModel → .model_dump()
  dataclass → dataclasses.asdict()
  Enum → .value
  PurePath → str()
  set/frozenset → list
  bytes → decoded string
  datetime/date/time/timedelta → .isoformat()
  Decimal → float
  UUID → str()
  dict → recurse on keys and values
  list/tuple/sequence → recurse on items
  generators → list, then recurse
```

The function accepts `include`, `exclude`, `by_alias`, `exclude_unset`, `exclude_defaults`, and `exclude_none` parameters that mirror Pydantic's `model_dump()` options.

### 8.6 Exception handling chain

FastAPI registers default exception handlers at startup:

| Exception | Handler | Status code | Response format |
|---|---|---|---|
| `RequestValidationError` | `request_validation_exception_handler` | 422 | `{"detail": [<validation errors>]}` |
| `HTTPException` | `http_exception_handler` | (from exception) | `{"detail": <message>}` |
| `WebSocketRequestValidationError` | `websocket_request_validation_exception_handler` | N/A (WebSocket close) | Validation errors as close reason |
| `WebSocketException` | Built into Starlette | N/A (WebSocket close) | Close with code and reason |

Custom handlers override defaults:

```python
@app.exception_handler(RequestValidationError)
async def custom_validation_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=422,
        content={"errors": exc.errors(), "body": exc.body},
    )
```

### 8.7 Error messages reference

All error messages raised by FastAPI core code (from source analysis):

| # | Exception type | Message | Source | Trigger |
|---|---|---|---|---|
| 1 | `FastAPIError` | `"Prefix and path cannot be both empty"` | `routing.py:1727` | Including a router with empty prefix and a route with empty path |
| 2 | `FastAPIError` | `"Response not awaited"` | `routing.py:125` | Dependency with `yield` uses bare `except:` that swallows `GeneratorExit` |
| 3 | `FastAPIError` | Invalid args type | `utils.py:75` | Internal: invalid argument types passed to utility functions |
| 4 | `PydanticV1NotSupportedError` | pydantic.v1 models no longer supported | `encoders.py:323` | Pydantic v1 model passed to `jsonable_encoder()` |
| 5 | `PydanticV1NotSupportedError` | pydantic.v1 response model not supported | `utils.py:67` | Pydantic v1 model used as `response_model` |
| 6 | `RuntimeError` | (dynamic message) | `cli.py:12` | `fastapi-cli` package not installed when running `python -m fastapi` |
| 7 | `ValueError` | `"SSE 'id' must not contain null characters"` | `sse.py:38` | Server-sent event ID contains `\0` |
| 8 | `ValueError` | `"Cannot set both 'data' and 'raw_data' on the same ServerSentEvent"` | `sse.py:138` | Both `data` and `raw_data` set on an SSE event |
| 9 | `ValueError` | `f'Expected UploadFile, received: {type(...)}'` | `datastructures.py:135` | Invalid type passed where `UploadFile` expected |
| 10 | `ValueError` | `errors` (from encoder) | `encoders.py:336` | Value cannot be encoded to JSON |
| 11 | `WebSocketRequestValidationError` | `solved_result.errors` | `routing.py:759` | WebSocket parameter validation failure |

### 8.8 Server-Sent Events (SSE) internals

FastAPI 0.135.3 includes built-in SSE support via `fastapi/sse.py`:

- **`ServerSentEvent`** — Pydantic model representing a single SSE event with fields: `data`, `raw_data`, `event`, `id`, `retry`, `comment`, `sep` (separator, defaults to `\r\n`).
- **`EventSourceResponse`** — Streaming response that sends `ServerSentEvent` objects over a `text/event-stream` connection. Accepts an async generator as its content source.

Validation rules:
- `id` field must not contain null characters (`\0`)
- `data` and `raw_data` are mutually exclusive on the same event
- `data` is serialized via `jsonable_encoder()` then JSON-dumped; `raw_data` is sent as-is

```python
from fastapi.sse import EventSourceResponse, ServerSentEvent

@app.get("/stream")
async def stream_events():
    async def event_generator():
        for i in range(100):
            yield ServerSentEvent(data={"count": i}, event="update")
            await asyncio.sleep(1)
    return EventSourceResponse(content=event_generator())
```

---

## 9. Integration Points

### 9.1 Database integration

#### SQLModel (recommended pattern from docs_src)

```python
from sqlmodel import SQLModel, Field, Session, create_engine, select

class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    secret_name: str
    age: int | None = Field(default=None, index=True)

engine = create_engine("sqlite:///database.db")

@asynccontextmanager
async def lifespan(app: FastAPI):
    SQLModel.metadata.create_all(engine)
    yield

app = FastAPI(lifespan=lifespan)

def get_session():
    with Session(engine) as session:
        yield session

@app.post("/heroes/", response_model=Hero)
def create_hero(hero: Hero, session: Session = Depends(get_session)):
    session.add(hero)
    session.commit()
    session.refresh(hero)
    return hero
```

#### SQLAlchemy async

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

engine = create_async_engine("postgresql+asyncpg://user:pass@host/db")
async_session = async_sessionmaker(engine, expire_on_commit=False)

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        yield session
```

### 9.2 Background tasks

```python
from fastapi import BackgroundTasks

def send_notification(email: str, message: str):
    """Runs after the response is sent."""
    # Send email logic here
    pass

@app.post("/items/")
async def create_item(background_tasks: BackgroundTasks):
    background_tasks.add_task(send_notification, "[email removed]", "Item created")
    return {"status": "created"}
```

> [!TIP]
> `BackgroundTasks` run in the same process after the response is sent. For tasks that are CPU-intensive, long-running, or need retry logic, use a proper task queue like Celery, ARQ, or Dramatiq. `BackgroundTasks` are best for fire-and-forget operations like sending emails or writing audit logs.

### 9.3 WebSocket integration

```python
from fastapi import WebSocket, WebSocketDisconnect

class ConnectionManager:
    def __init__(self):
        self.active_connections: list[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)

manager = ConnectionManager()

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.broadcast(f"Client #{client_id}: {data}")
    except WebSocketDisconnect:
        manager.disconnect(websocket)
```

### 9.4 Middleware integration

#### Custom middleware

```python
from starlette.middleware.base import BaseHTTPMiddleware

class RequestIDMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        request_id = request.headers.get("X-Request-ID", str(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)
```

#### Pure ASGI middleware (higher performance)

```python
class TimingMiddleware:
    def __init__(self, app):
        self.app = app

    async def __call__(self, scope, receive, send):
        if scope["type"] != "http":
            await self.app(scope, receive, send)
            return

        start = time.perf_counter()
        async def send_wrapper(message):
            if message["type"] == "http.response.start":
                duration = time.perf_counter() - start
                headers = MutableHeaders(scope=message)
                headers.append("X-Process-Time", str(duration))
            await send(message)

        await self.app(scope, receive, send_wrapper)

app.add_middleware(TimingMiddleware)
```

> [!NOTE]
> Pure ASGI middleware (the `__call__` approach) is faster than `BaseHTTPMiddleware` because it avoids reading the entire request body into memory. `BaseHTTPMiddleware` buffers the request body to construct a `Request` object, which can cause issues with streaming uploads and WebSocket connections.

### 9.5 Custom route classes

FastAPI allows extending `APIRoute` to customize request handling at the route level:

```python
from fastapi.routing import APIRoute

class GzipRoute(APIRoute):
    def get_route_handler(self):
        original_handler = super().get_route_handler()
        async def custom_handler(request: Request):
            if "gzip" in request.headers.get("Content-Encoding", ""):
                body = await request.body()
                request._body = gzip.decompress(body)
            return await original_handler(request)
        return custom_handler

app = FastAPI()
app.router.route_class = GzipRoute
```

Use cases from docs_src examples:
- **Gzip request decompression** — decompress gzip-encoded request bodies
- **Request timing** — log per-route request duration
- **Validation error logging** — capture and log validation failures before returning 422

### 9.6 Sub-application mounting

```python
# Main app
app = FastAPI()

# Sub-application with its own OpenAPI schema
api_v2 = FastAPI(title="API v2", version="2.0.0")

@api_v2.get("/items/")
async def read_items_v2():
    return [{"id": 1}]

app.mount("/api/v2", api_v2)
```

Sub-applications get their own OpenAPI schema at their own `docs_url`. They are completely independent FastAPI instances mounted at a path prefix.

### 9.7 Dependency overrides for testing

```python
from fastapi.testclient import TestClient

def get_settings():
    return Settings()

app = FastAPI()

# In tests:
def get_settings_override():
    return Settings(database_url="sqlite:///test.db")

app.dependency_overrides[get_settings] = get_settings_override
client = TestClient(app)
```

---

## 10. Module Reference

### 10.1 `fastapi/applications.py` — FastAPI Application

The `FastAPI` class (extends `Starlette`) is the central entry point. Key methods:

| Method | Purpose |
|---|---|
| `__init__(**kwargs)` | Constructs app with all parameters from Section 3.1 |
| `openapi()` | Generates and caches the OpenAPI schema dict |
| `setup()` | Registers OpenAPI and docs routes (called by `__init__`) |
| `add_api_route()` | Programmatic route registration |
| `api_route()` | Decorator for route registration |
| `add_api_websocket_route()` | WebSocket route registration |
| `websocket()` | WebSocket decorator |
| `include_router()` | Mount an `APIRouter` |
| `get/post/put/delete/patch/options/head/trace()` | HTTP method decorators |
| `build_middleware_stack()` | Constructs the middleware chain (from Starlette, extended) |

The `setup()` method is called automatically during `__init__`. It adds three routes if their respective URLs are not `None`:
- `openapi_url` → serves `self.openapi()` as JSON
- `docs_url` → serves Swagger UI HTML
- `redoc_url` → serves ReDoc HTML

The April Fool's joke at line 4618: calling `app()` with certain internal conditions triggers `FastAPIError: "Are you kidding me? Happy April Fool's"`. This is dead code in normal operation.

### 10.2 `fastapi/routing.py` — Router and Route Classes

**`APIRouter`** — Route collection that can be included in a `FastAPI` app or another router:

| Method | Purpose |
|---|---|
| `api_route(path, **kwargs)` | Route decorator |
| `include_router(router, prefix, tags, ...)` | Nest routers |
| `add_api_route(path, endpoint, **kwargs)` | Programmatic route add |
| `get/post/put/delete/patch/options/head/trace()` | HTTP method shortcuts |
| `websocket(path, ...)` | WebSocket route decorator |

**`APIRoute`** — Wraps a single endpoint:

| Attribute/Method | Purpose |
|---|---|
| `endpoint` | The original Python function |
| `dependant` | Compiled dependency tree |
| `response_model` | Pydantic model for response validation |
| `get_route_handler()` | Returns the ASGI handler; override for custom request processing |

**`APIWebSocketRoute`** — WebSocket equivalent of `APIRoute`.

Key internal behavior:
- `APIRoute.__init__()` calls `get_typed_signature()` to inspect the endpoint's type hints
- Dependencies are pre-compiled into a `Dependant` tree at route registration time, not at request time
- Route matching delegates to Starlette's router

### 10.3 `fastapi/params.py` — Parameter Classes

All parameter classes extend Pydantic's `FieldInfo`:

| Class | Location | Pydantic base |
|---|---|---|
| `Path` | URL path segments | `FieldInfo` |
| `Query` | URL query string | `FieldInfo` |
| `Header` | HTTP headers | `FieldInfo` |
| `Cookie` | HTTP cookies | `FieldInfo` |
| `Body` | Request body | `FieldInfo` |
| `Form` | Form-encoded body | `FieldInfo` |
| `File` | Multipart file upload | `FieldInfo` |
| `Depends` | Dependency injection | (standalone) |
| `Security` | Security dependency | extends `Depends` |

Each parameter class supports:
- `default` / `default_factory` — default values
- `alias` — alternative name in the request
- `title`, `description` — OpenAPI documentation
- `gt`, `ge`, `lt`, `le` — numeric constraints
- `min_length`, `max_length`, `pattern` — string constraints
- `examples` — OpenAPI examples
- `deprecated` — mark as deprecated
- `include_in_schema` — control OpenAPI visibility

### 10.4 `fastapi/openapi/` — OpenAPI Schema Generation

**`openapi/utils.py`** — Core functions:

| Function | Purpose |
|---|---|
| `get_openapi(title, version, routes, ...)` | Build the complete OpenAPI 3.1.0 dict |
| `get_openapi_path(route, ...)` | Convert a single route to OpenAPI path item |
| `get_flat_params(dependant)` | Flatten dependency tree into parameter list |

**`openapi/docs.py`** — HTML generators:

| Function | Output |
|---|---|
| `get_swagger_ui_html(openapi_url, title, ...)` | Complete Swagger UI HTML page |
| `get_redoc_html(openapi_url, title, ...)` | Complete ReDoc HTML page |
| `get_swagger_ui_oauth2_redirect_html()` | OAuth2 redirect handler HTML |

**`openapi/models.py`** — Full OpenAPI 3.1.0 spec as Pydantic models. 295+ model classes representing every object in the OpenAPI specification.

### 10.5 `fastapi/security/` — Security Utilities

See Section 7.1 for the complete class inventory. Additional implementation details:

**`oauth2.py`** internals:
- `OAuth2PasswordBearer.__call__()` extracts from `Authorization: Bearer <token>` header
- If `auto_error=True` (default), missing/invalid credentials raise `HTTPException(401)`
- If `auto_error=False`, returns `None` for missing credentials (allows optional auth)
- `OAuth2PasswordRequestForm` is a regular dependency that parses `application/x-www-form-urlencoded` body fields: `grant_type`, `username`, `password`, `scope` (space-separated string → `scopes` list), `client_id`, `client_secret`
- `SecurityScopes` aggregates all `scopes` from the dependency chain into a single `SecurityScopes.scopes` list and `SecurityScopes.scope_str` string

**`api_key.py`** internals:
- `APIKeyQuery(name="api_key")` extracts from `?api_key=<value>`
- `APIKeyHeader(name="X-API-Key")` extracts from custom header
- `APIKeyCookie(name="session")` extracts from cookie
- All support `auto_error=True/False` behavior

### 10.6 `fastapi/encoders.py` — JSON Encoding

`jsonable_encoder()` signature:

```python
def jsonable_encoder(
    obj: Any,
    include: IncEx | None = None,
    exclude: IncEx | None = None,
    by_alias: bool = True,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    custom_encoder: dict[Any, Callable] | None = None,
    sqlalchemy_safe: bool = True,
) -> Any:
```

The `sqlalchemy_safe=True` default excludes keys starting with `_sa` (SQLAlchemy internal attributes).

### 10.7 `fastapi/datastructures.py` — UploadFile

`UploadFile` extends Starlette's `UploadFile` with Pydantic v2 validation support:

| Attribute | Type | Description |
|---|---|---|
| `filename` | `str \| None` | Original filename from the upload |
| `size` | `int \| None` | File size in bytes |
| `headers` | `Headers` | Multipart headers |
| `content_type` | `str \| None` | MIME type from Content-Type header |

| Method | Description |
|---|---|
| `await read(size)` | Read bytes |
| `await write(data)` | Write bytes |
| `await seek(offset)` | Seek to position |
| `await close()` | Close the file |

The `__get_pydantic_core_schema__` class method registers a custom Pydantic validator that raises `ValueError: f'Expected UploadFile, received: {type(...)}'` for non-UploadFile inputs.

### 10.8 `fastapi/_compat/v2.py` — Pydantic Compatibility

Key functions in the compatibility layer:

| Function | Purpose |
|---|---|
| `get_model_fields(model)` | Extract `FieldInfo` dict from a Pydantic model |
| `get_schema_from_model_field(field, ...)` | Generate JSON Schema for a `ModelField` |
| `serialize_sequence_value(field, value)` | Serialize list/set values according to field schema |
| `get_missing_field_error(loc)` | Generate a standardized "field required" error |
| `create_body_model(fields, model_name)` | Dynamically create a Pydantic model from body fields |

### 10.9 `fastapi/sse.py` — Server-Sent Events

| Class | Purpose |
|---|---|
| `ServerSentEvent` | Pydantic model for a single SSE event |
| `EventSourceResponse` | Streaming response that yields SSE events |

`ServerSentEvent` fields: `data` (any JSON-serializable), `raw_data` (str, sent as-is), `event` (event type), `id` (event ID, no nulls), `retry` (reconnect interval ms), `comment` (SSE comment line), `sep` (line separator).

### 10.10 `fastapi/exception_handlers.py` — Default Handlers

```python
async def http_exception_handler(request, exc) -> JSONResponse | PlainTextResponse
async def request_validation_exception_handler(request, exc) -> JSONResponse
async def websocket_request_validation_exception_handler(websocket, exc) -> None
```

The HTTP exception handler returns `PlainTextResponse` if `exc.detail` is not a dict/list, otherwise `JSONResponse`. This allows both `HTTPException(detail="Not found")` and `HTTPException(detail={"error": "not_found", "field": "id"})`.

---

## 11. Testing Strategy

### 11.1 TestClient

FastAPI re-exports Starlette's `TestClient` (powered by `httpx`):

```python
from fastapi.testclient import TestClient

app = FastAPI()

@app.get("/items/{id}")
async def read_item(id: int):
    return {"id": id}

client = TestClient(app)

def test_read_item():
    response = client.get("/items/42")
    assert response.status_code == 200
    assert response.json() == {"id": 42}

def test_read_item_invalid():
    response = client.get("/items/not-an-int")
    assert response.status_code == 422
```

### 11.2 Async testing

```python
import pytest
from httpx import AsyncClient, ASGITransport

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

### 11.3 Dependency overrides

```python
def test_with_override():
    def override_get_db():
        return TestDatabase()

    app.dependency_overrides[get_db] = override_get_db
    client = TestClient(app)

    response = client.get("/items/")
    assert response.status_code == 200

    # Clean up
    app.dependency_overrides.clear()
```

### 11.4 WebSocket testing

```python
def test_websocket():
    client = TestClient(app)
    with client.websocket_connect("/ws") as websocket:
        websocket.send_text("hello")
        data = websocket.receive_text()
        assert data == "Message text was: hello"
```

### 11.5 Testing file uploads

```python
def test_upload():
    client = TestClient(app)
    response = client.post(
        "/uploadfile/",
        files={"file": ("test.txt", b"file content", "text/plain")},
    )
    assert response.status_code == 200
```

---

## 12. Code Patterns and Conventions

### 12.1 Project structure conventions

```
project/
  app/
    __init__.py
    main.py              # FastAPI() instance + lifespan
    config.py            # Settings (pydantic-settings)
    dependencies.py      # Shared dependencies
    models.py            # Pydantic models (schemas)
    database.py          # Database engine + session
    routers/
      __init__.py
      items.py           # APIRouter for /items
      users.py           # APIRouter for /users
    middleware/
      __init__.py
      timing.py
      auth.py
    services/            # Business logic (not FastAPI-specific)
      item_service.py
      user_service.py
  tests/
    conftest.py
    test_items.py
    test_users.py
  alembic/               # Database migrations
  requirements.txt
  Dockerfile
```

### 12.2 Router organization pattern

```python
# app/routers/items.py
from fastapi import APIRouter, Depends, HTTPException, status

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(verify_token)],
    responses={404: {"description": "Not found"}},
)

@router.get("/")
async def list_items(): ...

@router.get("/{id}")
async def get_item(id: int): ...

# app/main.py
from app.routers import items, users

app = FastAPI()
app.include_router(items.router)
app.include_router(users.router, prefix="/api/v1")
```

### 12.3 Response model patterns

```python
# Separate input/output models
class ItemCreate(BaseModel):
    name: str
    price: float

class ItemResponse(BaseModel):
    id: int
    name: str
    price: float
    model_config = ConfigDict(from_attributes=True)

class ItemList(BaseModel):
    items: list[ItemResponse]
    total: int

@app.post("/items/", response_model=ItemResponse, status_code=201)
async def create_item(item: ItemCreate): ...
```

### 12.4 Error handling patterns

```python
# Custom exception class
class ItemNotFoundError(Exception):
    def __init__(self, item_id: int):
        self.item_id = item_id

# Register handler
@app.exception_handler(ItemNotFoundError)
async def item_not_found_handler(request: Request, exc: ItemNotFoundError):
    return JSONResponse(
        status_code=404,
        content={"detail": f"Item {exc.item_id} not found"},
    )
```

### 12.5 Dependency injection patterns

```python
# Class-based dependencies
class Pagination:
    def __init__(self, skip: int = Query(0, ge=0), limit: int = Query(100, le=1000)):
        self.skip = skip
        self.limit = limit

@app.get("/items/")
async def list_items(pagination: Pagination = Depends()):
    return items[pagination.skip : pagination.skip + pagination.limit]

# Dependency chain
async def get_db(): ...
async def get_current_user(db = Depends(get_db)): ...
async def get_current_active_user(user = Depends(get_current_user)): ...

@app.get("/users/me")
async def read_me(user = Depends(get_current_active_user)):
    return user
```

---

## 13. Troubleshooting

### 13.1 Common errors and solutions

| Error | Cause | Solution |
|---|---|---|
| `422 Unprocessable Entity` | Request body/params fail Pydantic validation | Check the `detail` array in the response for field-level errors. Ensure request matches the expected schema. |
| `No module named 'multipart'` | `python-multipart` not installed | `pip install python-multipart`. Required for `Form()`, `File()`, `UploadFile`. |
| `"Could not import module"` in Uvicorn | Incorrect module path | Verify `uvicorn app.main:app` matches your file structure. |
| Swagger UI shows wrong URLs behind proxy | `root_path` not configured | Set `root_path` in FastAPI constructor or `--root-path` in Uvicorn. |
| `Depends(use_cache=False)` ignored | Dependency is not the same callable object | Ensure the dependency function is the same object (not a lambda wrapper). |
| WebSocket disconnect not caught | Not catching `WebSocketDisconnect` | Wrap `receive_text/json()` in `try/except WebSocketDisconnect`. |
| `FastAPIError: "Prefix and path cannot be both empty"` | Router with `prefix=""` containing a route with `path=""` | Provide at least a prefix on the router or a path on the route. |
| `FastAPIError: "Response not awaited"` | Yield dependency with bare `except:` | Change to `except Exception:` — never catch `BaseException` in yield dependencies. |
| Lifespan not running | Using `on_startup` + `lifespan` together | Use only `lifespan`. `on_startup`/`on_shutdown` are deprecated and ignored when `lifespan` is set. |
| Async endpoint blocks event loop | Sync I/O in `async def` endpoint | Either make the endpoint `def` (sync) or use async I/O libraries. |
| `PydanticV1NotSupportedError` | Using Pydantic v1 models | Migrate to Pydantic v2. FastAPI 0.135.3 does not support `pydantic.v1` models. |

### 13.2 Performance debugging

```python
# Add timing middleware to identify slow endpoints
import time
from starlette.middleware.base import BaseHTTPMiddleware

class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        start = time.perf_counter()
        response = await call_next(request)
        duration = time.perf_counter() - start
        if duration > 1.0:  # Log slow requests
            logger.warning(
                f"Slow request: {request.method} {request.url.path} "
                f"took {duration:.2f}s"
            )
        response.headers["X-Process-Time"] = str(duration)
        return response
```

### 13.3 Debug mode

```python
app = FastAPI(debug=True)
```

In debug mode:
- `ServerErrorMiddleware` returns full tracebacks in 500 responses (HTML format)
- Starlette enables additional debug logging

> [!CAUTION]
> **Never** enable `debug=True` in production. Stack traces expose internal code paths, file locations, variable values, and potentially sensitive configuration to attackers.

---

## 14. Quick Reference

### 14.1 Import cheat sheet

```python
# Core
from fastapi import FastAPI, Request, Response, Depends, HTTPException, status

# Parameters
from fastapi import Path, Query, Header, Cookie, Body, Form, File, UploadFile

# Security
from fastapi.security import (
    OAuth2PasswordBearer, OAuth2PasswordRequestForm, OAuth2AuthorizationCodeBearer,
    HTTPBasic, HTTPBearer, HTTPBasicCredentials, HTTPAuthorizationCredentials,
    APIKeyHeader, APIKeyQuery, APIKeyCookie, SecurityScopes, OpenIdConnect,
)

# Routing
from fastapi import APIRouter
from fastapi.routing import APIRoute, APIWebSocketRoute

# Responses
from fastapi.responses import (
    JSONResponse, HTMLResponse, PlainTextResponse, RedirectResponse,
    StreamingResponse, FileResponse, ORJSONResponse, UJSONResponse,
)

# Middleware
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

# Exceptions
from fastapi.exceptions import (
    HTTPException, WebSocketException, RequestValidationError,
    ResponseValidationError,
)

# Encoding
from fastapi.encoders import jsonable_encoder

# Background
from fastapi import BackgroundTasks

# SSE
from fastapi.sse import EventSourceResponse, ServerSentEvent

# Testing
from fastapi.testclient import TestClient

# WebSocket
from fastapi import WebSocket, WebSocketDisconnect

# OpenAPI
from fastapi.openapi.utils import get_openapi
from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html

# Static files and templates (from Starlette)
from starlette.staticfiles import StaticFiles
from starlette.templating import Jinja2Templates
```

### 14.2 HTTP status code reference

```python
from fastapi import status

# Success
status.HTTP_200_OK
status.HTTP_201_CREATED
status.HTTP_204_NO_CONTENT

# Redirection
status.HTTP_301_MOVED_PERMANENTLY
status.HTTP_307_TEMPORARY_REDIRECT

# Client errors
status.HTTP_400_BAD_REQUEST
status.HTTP_401_UNAUTHORIZED
status.HTTP_403_FORBIDDEN
status.HTTP_404_NOT_FOUND
status.HTTP_409_CONFLICT
status.HTTP_422_UNPROCESSABLE_ENTITY
status.HTTP_429_TOO_MANY_REQUESTS

# Server errors
status.HTTP_500_INTERNAL_SERVER_ERROR
status.HTTP_502_BAD_GATEWAY
status.HTTP_503_SERVICE_UNAVAILABLE
```

### 14.3 OpenAPI 3.1.0 schema structure

```json
{
    "openapi": "3.1.0",
    "info": {
        "title": "...",
        "summary": "...",
        "description": "...",
        "version": "...",
        "termsOfService": "...",
        "contact": {},
        "license": {}
    },
    "servers": [{"url": "..."}],
    "paths": {
        "/items/{id}": {
            "get": {
                "summary": "...",
                "operationId": "...",
                "parameters": [],
                "responses": {},
                "security": []
            }
        }
    },
    "components": {
        "schemas": {},
        "securitySchemes": {}
    },
    "tags": [],
    "externalDocs": {},
    "webhooks": {}
}
```

### 14.4 Codebase statistics

| Metric | Value |
|---|---|
| Version | 0.135.3 |
| Total files | 2,846 |
| Source characters | ~1.5M |
| Core package files | 23 (fastapi/) |
| Core package size | ~522K chars |
| OpenAPI module | 4 files, ~53K chars |
| Security module | 7 files, ~52K chars |
| Compatibility layer | 3 files, ~26K chars |
| Classes | 295 |
| Functions | 847 |
| docs_src example endpoints | 421 |
| Error messages | 13 |
| Complexity tier | Large |

---

_Generated May 2026 from tiangolo/fastapi at 9653034. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
