跪拜 Guibai
← All articles
Frontend · Python

FastAPI Under the Hood: ASGI, Dependency Injection, and the Lifespan Pattern

By 一tiao咸鱼 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

A Python backend that handles concurrent I/O without spawning extra workers changes the cost calculus for API services. Understanding the `yield`-based dependency lifecycle and the static-before-dynamic routing rule prevents two of the most common production bugs in FastAPI applications.

Summary

FastAPI's speed comes from ASGI, which lets a single worker juggle multiple requests by yielding the CPU during I/O waits, unlike WSGI's one-request-per-worker model. The framework itself is a thin layer over Starlette (routing, middleware) and Pydantic (validation, serialization), adding syntactic sugar that cuts boilerplate in half compared to Flask.

The dependency injection system built around `Depends` uses generator functions with `yield` to hand resources like database sessions into route handlers and then reliably clean them up in a `finally` block, even when exceptions occur. Dependencies can nest and are cached per request, so a single session is reused across multiple parameters without repeated creation.

Route organization relies on `APIRouter` for modularity, but registration order matters: static paths must precede dynamic ones or `/users/me` gets swallowed by `/users/{user_id}`. The new `lifespan` context manager centralizes startup and shutdown logic in one async generator, replacing the now-deprecated `on_event` decorators and making shared state easier to pass around.

Takeaways
ASGI allows one worker to process multiple requests by yielding the CPU during I/O waits, while WSGI ties up a worker per request.
FastAPI is a thin wrapper over Starlette (async web core) and Pydantic (type-driven validation and serialization).
Synchronous route functions using `def` are automatically offloaded to a thread pool, preventing event-loop blockage.
The `Depends` system calls a generator function, injects the yielded value, and always executes the `finally` block after the route completes.
Dependencies are cached per request, so multiple parameters that depend on the same callable receive the same instance.
`APIRouter` with a `prefix` avoids repeating URL segments, but static routes must be registered before dynamic ones to prevent mismatches.
The `lifespan` async context manager replaces the deprecated `on_event` hooks, keeping startup and shutdown logic in one place.
`response_model` automatically filters out extra fields like `hashed_password` from the serialized output.
Global exception handlers registered with `@app.exception_handler` eliminate try/except blocks in route functions.
Pydantic validation failures automatically return HTTP 422 with structured error details.
Conclusions

FastAPI's design makes the framework feel almost invisible: the heavy lifting is delegated to Starlette and Pydantic, and FastAPI itself contributes mostly ergonomics. That explains both its speed and its shallow learning curve for developers who already know type hints.

The `yield`-based dependency pattern is a clever abuse of Python generators. It turns a language feature designed for lazy iteration into a deterministic resource-management primitive, giving FastAPI something resembling middleware but scoped to individual route parameters.

Routing order as a footgun is a direct consequence of FastAPI's first-match-wins strategy. Most frameworks warn about this; FastAPI silently converts `me` to an integer and returns a 422, which is correct behavior but a confusing debugging experience for newcomers.

Offloading synchronous `def` routes to a thread pool is a pragmatic escape hatch, but it hides a design tension: the framework advertises async performance while most SQLAlchemy users still write blocking code. The thread-pool workaround keeps the event loop clear but adds scheduling overhead.

Concepts & terms
ASGI
Asynchronous Server Gateway Interface, the async successor to WSGI. It allows a single server worker to handle multiple concurrent requests by suspending and resuming coroutines during I/O operations.
Dependency Injection via `Depends`
A FastAPI mechanism where a callable (often a generator with `yield`) is automatically invoked before a route handler, its return value passed as a parameter, and any cleanup in a `finally` block guaranteed to run after the response.
`lifespan` context manager
An async context manager passed to the FastAPI app that runs code before `yield` at startup and after `yield` at shutdown, replacing the deprecated `on_event` decorators for lifecycle management.
`APIRouter`
A FastAPI class for grouping related routes with a shared path prefix and tags. It enables splitting a large API across multiple files and is mounted into the main app via `include_router`.
`response_model`
A Pydantic model specified in a route decorator that FastAPI uses to filter and serialize the returned data, stripping any fields not defined in the model before sending the HTTP response.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗