fastapi/fastapi
Patterns and conventions
Type style
pyproject.toml enables tool.mypy with strict = true and the pydantic.mypy plugin. Code in fastapi/ is fully type-annotated. Two style points:
Annotated[T, Doc(...)]for public callables. Most parameters infastapi/param_functions.py,fastapi/applications.py, and the security classes useAnnotated[T, Doc("""...""")]from theannotated-docpackage. TheDoc(...)payload is a markdown string that mkdocstrings renders into the API reference. Example fromfastapi/datastructures.py:filename: Annotated[str | None, Doc("The original file name.")]PEP 604 unions.
requires-python = ">=3.10", so the source usesstr | Nonerather thanOptional[str].
Public API discipline
fastapi/__init__.py is the only module user code is meant to import from. Every name there is from … import X as X — the as X rebinding silences F401 and makes the export intentional. When adding a new symbol, decide whether it belongs in the public surface or behind a sub-module like fastapi.security or fastapi.encoders. Removing or renaming anything in fastapi/__init__.py is a breaking change.
Default placeholders
fastapi/datastructures.py:DefaultPlaceholder and the helper Default(value) exist so the framework can tell "user passed None" apart from "user passed nothing." Always wrap framework-supplied defaults with Default(...). To check, prefer isinstance(x, DefaultPlaceholder) over equality.
get_value_or_default(...) in fastapi/utils.py walks a chain of values and returns the first non-placeholder.
_compat boundary
Anything that depends on Pydantic internals goes through fastapi/_compat. Direct imports of pydantic.fields.FieldInfo are common (see fastapi/params.py), but utilities like get_definitions, get_schema_from_model_field, create_body_model, and the ModelField wrapper are imported from fastapi._compat. This keeps Pydantic-version drift containable.
Error handling
- Raise
HTTPException(fastapi/exceptions.py) for client-visible errors. The default handler is registered inFastAPI.__init__; do not register one yourself unless overriding behaviour. - Raise
FastAPIErrorfor framework-internal misuse. Subclass it (DependencyScopeError,PydanticV1NotSupportedError) when a specific case needs to be catchable. - Validation errors (
RequestValidationError,ResponseValidationError,WebSocketRequestValidationError) carry an optionalendpoint_ctx: EndpointContextso error messages name the offending endpoint. When you build them, plumb the context through.
Async vs sync callables
The framework supports both. The Dependant model caches is_coroutine_callable, is_gen_callable, is_async_gen_callable as @cached_property — never compute these inline in a hot path. Sync functions are dispatched to a threadpool via starlette.concurrency.run_in_threadpool. See request_response() in fastapi/routing.py.
Decorator-driven registration
The framework relies on decorators that do work at import time. Keep decorator implementations short — most of the heavy lifting in APIRouter.add_api_route happens during add_api_route, not during @app.get(...). The decorator returns the same callable so users can still call it directly in tests.
Re-exports of Starlette
When a Starlette type is part of the FastAPI public API, re-export it through a one-line shim (see fastapi/staticfiles.py, fastapi/templating.py, fastapi/testclient.py). Do not import from starlette.* in user-facing examples — point users at fastapi.*.
Deprecation pattern
Deprecate through typing_extensions.deprecated (or pydantic.deprecated.*) decorators applied directly to the parameter or function. Issue FastAPIDeprecationWarning (a subclass of UserWarning — Python ignores DeprecationWarning by default in libraries; see the docstring in fastapi/exceptions.py). Examples:
regex=parameter onParam.__init__(fastapi/params.py).UJSONResponseandORJSONResponse(fastapi/responses.py).generate_operation_id_for_path(fastapi/utils.py).
Lint rules
tool.ruff.lint.select = ["E", "W", "F", "I", "B", "C4", "UP"]. Notable per-file exceptions live in tool.ruff.lint.per-file-ignores — most are tutorial examples that intentionally show "wrong" code (e.g. unused variables, shadowed names) for pedagogy. Add to that list rather than silencing rules globally.
Test conventions
See Testing for the structural conventions. The two most-followed rules:
- Every behaviour change in
fastapi/ships with a regression test intests/. - Every new tutorial in
docs_src/ships with a corresponding test undertests/test_tutorial/. The naming convention is mechanical (docs_src/foo/tutorial001.py→tests/test_tutorial/test_foo/test_tutorial001.py).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.
Previous
Debugging
Next
Tooling