Support Annotated dependencies in APIRouter

This commit is contained in:
ProfiAnton 2025-10-13 19:16:01 +02:00
parent 81f85831f5
commit afa7461f28
2 changed files with 63 additions and 4 deletions

View File

@ -37,6 +37,7 @@ from fastapi.datastructures import Default, DefaultPlaceholder
from fastapi.dependencies.models import Dependant
from fastapi.dependencies.utils import (
_should_embed_body_fields,
analyze_param,
get_body_field,
get_dependant,
get_flat_dependant,
@ -670,6 +671,22 @@ class APIRoute(routing.Route):
return match, child_scope
def get_api_router_dep(dep: params.Depends | Any) -> params.Depends:
if isinstance(dep, params.Depends):
return dep
d = analyze_param(
param_name="APIRouter Dependency",
annotation=dep,
value=inspect.Signature.empty,
is_path_param=False,
).depends
assert d is not None, (
"APIRouter dependency must be a Depends or be Annotated with Depends"
)
return d
class APIRouter(routing.Router):
"""
`APIRouter` class, used to group *path operations*, for example to structure
@ -716,11 +733,15 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[params.Depends | Any]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
*path operations* in this router.
A list of dependencies to be applied to all the *path operations* in
this router.
Dependencies can be provided as `Depends(...)` instances, or using
`Annotated[..., Depends(...)]`. FastAPI will analyze and convert
these automatically when the router is included.
Read more about it in the
[FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
@ -927,7 +948,7 @@ class APIRouter(routing.Router):
)
self.prefix = prefix
self.tags: List[Union[str, Enum]] = tags or []
self.dependencies = list(dependencies or [])
self.dependencies = [get_api_router_dep(dep) for dep in dependencies or []]
self.deprecated = deprecated
self.include_in_schema = include_in_schema
self.responses = responses or {}

View File

@ -0,0 +1,38 @@
from fastapi import APIRouter, Depends, FastAPI
from fastapi.testclient import TestClient
from typing_extensions import Annotated
def get_value() -> int:
return 1
ValueDep = Annotated[int, Depends(get_value)]
router = APIRouter(dependencies=[ValueDep, Depends(lambda: "sdfgh")])
@router.get("/")
def read_root(dep: ValueDep):
return {"dep": dep}
@router.get("/no_dep")
def no_dep():
return {"status": 200}
app = FastAPI()
app.include_router(router)
def test_apirouter_annotated_dependencies():
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"dep": 1}
response = client.get("/no_dep")
assert response.status_code == 200
assert response.json() == {"status": 200}