Skip to main content

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: Identifies async def functions.
  • is_gen_callable: Identifies standard generator functions (yield).
  • is_async_gen_callable: Identifies async generator 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:

  1. The callable itself (self.call).
  2. A sorted tuple of OAuth scopes.
  3. The computed_scope.

Dependency Scopes

Dependencies can have a scope of either "request" or "function".

  • Generator Dependencies: By default, any dependency using yield is assigned a "request" scope via the computed_scope property.
  • 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 in get_dependant, which raises a DependencyScopeError if 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.