Files
fastapi-conventions/sources/fastapi.md
T
2026-06-01 21:42:05 +00:00

5.3 KiB

FastAPI source notes

Repo: fastapi/fastapi Local checkout: /home/ubuntu/repos/rodin-sources/fastapi

Why this repo was chosen

  • Core framework source plus first-party docs/tests. It is the best place to separate actual repeated FastAPI conventions from tutorial folklore.
  • Especially useful here because the same patterns appear in docs examples, framework internals, and tests: router composition, dependency injection, semantic exceptions, and dependency-driven test seams.

Repeated patterns

1) App assembly is declarative: app-level and router-level configuration carry shared concerns

  • docs_src/bigger_applications/app_an_py310/main.py:7-18 creates the app with a global dependency, then includes routers with per-router prefix/tags/dependencies/responses.
  • docs_src/bigger_applications/app_an_py310/routers/items.py:5-10 shows the same concern split one level down: the router owns prefix/tags/dependencies/common responses.
  • fastapi/applications.py:330-348 documents that FastAPI(..., dependencies=[...]) applies those dependencies to every path operation, including sub-routers.

Why chosen:

  • This is not a one-off tutorial style; the public constructor explicitly supports the same pattern the docs teach.

Implication for synthesis:

  • Favor centralized app/router configuration for auth headers, tags, common responses, and prefixes.
  • Do not describe thin handlers as a style preference only; the framework API is built to move cross-cutting concerns out of handlers.

2) Dependencies are first-class request wiring, including teardown-aware resources

  • docs_src/bigger_applications/app_an_py310/dependencies.py:6-13 keeps request validation in dedicated dependency callables that raise HTTP errors directly.
  • fastapi/routing.py:95-136 wraps request handling in nested AsyncExitStacks specifically so dependency setup/teardown, including yield dependencies, participates in request lifecycle.
  • tests/test_dependency_security_overrides.py:24-29 defines a route entirely in terms of Security(...) and Depends(...) collaborators.

Why chosen:

  • This combines public examples with internal lifecycle machinery. Dependencies are not sugar over helper calls; they are a core execution model.

Caveat / counterexample:

  • fastapi/routing.py:124-130 raises a FastAPIError if application code swallows an exception in a yield dependency and fails to re-raise. So "just hide cleanup in a dependency" is incomplete; dependency cleanup must preserve exception flow.

Implication for synthesis:

  • Prefer dependencies for auth, validated request context, DB/session access, and request-scoped resources.
  • Mention that yield dependencies are appropriate when setup/teardown must be coupled to a request.

3) Handlers and dependencies raise semantic HTTP exceptions; framework handlers translate them

  • docs_src/bigger_applications/app_an_py310/routers/items.py:21-25 raises HTTPException(404, ...) when an item is missing.
  • docs_src/bigger_applications/app_an_py310/routers/items.py:28-38 adds operation-specific response metadata and raises HTTPException(403, ...) for forbidden updates.
  • fastapi/exception_handlers.py:11-26 turns HTTPException and RequestValidationError into HTTP responses, including a 422 JSON body for validation failures.
  • fastapi/exception_handlers.py:13-17 also shows a subtle rule: statuses that must not include a body return a bare Response, not JSON.

Why chosen:

  • The docs examples and framework exception handlers line up exactly: route code signals semantics, framework code owns response formatting.

Implication for synthesis:

  • Recommend raising semantic exceptions from route/dependency code instead of hand-building error JSON in each handler.
  • Note that response-body behavior is status-sensitive and partly framework-owned.

4) Preferred test seam: override dependencies, not handler internals

  • tests/test_dependency_security_overrides.py:24-29 keeps the route signature explicit about collaborators.
  • tests/test_dependency_security_overrides.py:44-63 replaces both ordinary dependencies and security dependencies through app.dependency_overrides, then resets overrides after each test.

Why chosen:

  • This is a repo-level testing pattern, not an incidental example.

Caveat / counterexample:

  • The reset step is part of the pattern, not cleanup fluff: tests/test_dependency_security_overrides.py:52-63 clears app.dependency_overrides = {} after each override-based test.

Implication for synthesis:

  • When describing testing conventions, emphasize overrideable dependency seams as the intended unit of substitution.

Strong citation candidates

  • Global dependencies apply across sub-routers: fastapi/applications.py:330-348
  • Dependency lifecycle is request-lifecycle machinery, not style guidance: fastapi/routing.py:95-136
  • yield dependency exception-swallowing failure mode: fastapi/routing.py:124-130
  • Central exception translation, including no-body statuses: fastapi/exception_handlers.py:11-17

Pattern candidates supported by this repo

  • centralize cross-cutting concerns in app/router configuration
  • use dependencies as the main request-wiring mechanism
  • use yield dependencies for request-scoped resources with teardown
  • raise semantic HTTPExceptions from handlers/dependencies and let framework handlers shape responses
  • test by overriding dependencies and resetting overrides explicitly