The Dependant Model
The Dependant class, located in fastapi/dependencies/models.py, is the core internal representation of every dependency and path operation in the system. It acts as a "blueprint" that FastAPI uses to understand how to resolve parameters, execute callables, and manage the lifecycle of dependencies.
Core Structure and Parameter Tracking
Every time a route is defined or a Depends() is used, FastAPI creates a Dependant object. This object tracks all the data required to satisfy the signature of the underlying callable.
The class organizes parameters into specific lists based on their source, using ModelField objects to handle validation and metadata:
path_params: Parameters extracted from the URL path.query_params: Parameters from the URL query string.header_params: Parameters from HTTP headers.-
cookie_params: Parameters from cookies.
body_params: Parameters expected in the request body.
Beyond simple parameters, the dependencies attribute (a list["Dependant"]) allows Dependant objects to form a tree structure. This tree represents the hierarchy of Depends() calls within a single endpoint.
The Lifecycle of a Dependant
The creation and use of Dependant objects follow a specific flow within the codebase:
1. Introspection via get_dependant
The factory function get_dependant (in fastapi/dependencies/utils.py) is responsible for creating these objects. It uses inspect.signature to analyze a callable and populates the Dependant attributes.
If a parameter is another Depends() instance, get_dependant is called recursively, and the resulting object is added to the dependencies list of the parent.
2. Flattening for OpenAPI
For tasks like generating OpenAPI schemas or performing global validation, FastAPI needs a flat view of all parameters required by an endpoint and its entire dependency tree.
The function get_flat_dependant (in fastapi/dependencies/utils.py) creates a new Dependant object where all parameters from sub-dependencies are merged into the top-level lists. This ensures that the OpenAPI generator in fastapi/openapi/utils.py can see every requirement for the route in one place.
3. Resolution via solve_dependencies
During a request, solve_dependencies (in fastapi/dependencies/utils.py) traverses the Dependant tree. It resolves sub-dependencies first, then uses the gathered values to call the Dependant.call function.
Execution Strategy
The Dependant model determines how a dependency should be executed through several cached properties that inspect the nature of the call attribute:
is_coroutine_callable: Identifiesasync deffunctions.is_gen_callable: Identifies standard generator functions (yield).is_async_gen_callable: Identifiesasyncgenerator functions (async yield).
In solve_dependencies, these properties dictate whether the dependency is run in a threadpool (for sync functions), awaited directly (for coroutines), or entered via an AsyncExitStack (for generators).
# Example of how solve_dependencies uses Dependant metadata
if use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable:
solved = await _solve_generator(
dependant=use_sub_dependant,
stack=use_astack,
sub_values=solved_result.values,
)
elif use_sub_dependant.is_coroutine_callable:
solved = await call(**solved_result.values)
else:
solved = await run_in_threadpool(call, **solved_result.values)
Scoping and Caching
The Dependant model manages how results are reused across a single request.
Caching Logic
If use_cache is True (the default), FastAPI uses the cache_key property to store and retrieve results in a dependency_cache dictionary. The cache_key is a tuple consisting of:
- The callable itself (
self.call). - A sorted tuple of OAuth scopes.
- The
computed_scope.
Dependency Scopes
Dependencies can have a scope of either "request" or "function".
- Generator Dependencies: By default, any dependency using
yieldis assigned a"request"scope via thecomputed_scopeproperty. - Scope Constraints: The system enforces a strict hierarchy. A dependency with a
"request"scope (like a generator) cannot depend on a dependency with a"function"scope. This is validated inget_dependant, which raises aDependencyScopeErrorif this rule is violated.
@cached_property
def computed_scope(self) -> str | None:
if self.scope:
return self.scope
if self.is_gen_callable or self.is_async_gen_callable:
return "request"
return None
Security and OAuth Scopes
The Dependant class also tracks security requirements. The oauth_scopes property aggregates scopes from the current dependency (own_oauth_scopes) and its parents (parent_oauth_scopes). This allows FastAPI to inject a SecurityScopes object into dependencies that require knowledge of the required scopes for the current operation.