mirror of https://github.com/tiangolo/fastapi.git
add support for starlette's scoped middleware
This commit is contained in:
parent
7c75b55580
commit
71fb6b64c7
|
|
@ -84,6 +84,20 @@ The following arguments are supported:
|
||||||
* `minimum_size` - Do not GZip responses that are smaller than this minimum size in bytes. Defaults to `500`.
|
* `minimum_size` - Do not GZip responses that are smaller than this minimum size in bytes. Defaults to `500`.
|
||||||
* `compresslevel` - Used during GZip compression. It is an integer ranging from 1 to 9. Defaults to `9`. Lower value results in faster compression but larger file sizes, while higher value results in slower compression but smaller file sizes.
|
* `compresslevel` - Used during GZip compression. It is an integer ranging from 1 to 9. Defaults to `9`. Lower value results in faster compression but larger file sizes, while higher value results in slower compression but smaller file sizes.
|
||||||
|
|
||||||
|
## Router and Route-Level Middleware Example
|
||||||
|
|
||||||
|
**FastAPI supports adding scoped middleware per route and router. Middleware execution order:**
|
||||||
|
|
||||||
|
- **App‑level middleware** runs on *every* request as soon as it enters your application, before any router or route is matched.
|
||||||
|
- **Router‑level middleware** runs next, wrapping all requests to routes included on that router.
|
||||||
|
- **Route‑level middleware** runs last, just around the specific path operation.
|
||||||
|
|
||||||
|
This gives better control over where and when logic executes.
|
||||||
|
|
||||||
|
The example below shows middleware applied at each scope. Notice how the inner route’s middleware is able to match path params ;)
|
||||||
|
|
||||||
|
{* ../../docs_src/advanced_middleware/tutorial004.py *}
|
||||||
|
|
||||||
## Other middlewares
|
## Other middlewares
|
||||||
|
|
||||||
There are many other ASGI middlewares.
|
There are many other ASGI middlewares.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
from fastapi import APIRouter, FastAPI, Request
|
||||||
|
from starlette.middleware import Middleware
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
@app.middleware("http")
|
||||||
|
async def app_middleware(request: Request, call_next):
|
||||||
|
print("App before")
|
||||||
|
response = await call_next(request)
|
||||||
|
print("App after")
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
async def outer_middleware(request: Request, call_next):
|
||||||
|
print("Outer before")
|
||||||
|
response = await call_next(request)
|
||||||
|
print("Outer after")
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
outer = APIRouter(
|
||||||
|
prefix="/outer",
|
||||||
|
middleware=[Middleware(BaseHTTPMiddleware, dispatch=outer_middleware)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def name_middleware(request: Request, call_next):
|
||||||
|
print(f"Hi {request.path_params.get('name')}!")
|
||||||
|
response = await call_next(request)
|
||||||
|
print(f"Bye {request.path_params.get('name')}!")
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
inner = APIRouter(prefix="/inner")
|
||||||
|
|
||||||
|
|
||||||
|
@inner.get(
|
||||||
|
"/{name}",
|
||||||
|
middleware=[Middleware(BaseHTTPMiddleware, dispatch=name_middleware)],
|
||||||
|
)
|
||||||
|
async def hello(name: str):
|
||||||
|
print("Handler")
|
||||||
|
return {"message": f"Hello {name} from inner!"}
|
||||||
|
|
||||||
|
|
||||||
|
@outer.get("/")
|
||||||
|
async def outer_hello():
|
||||||
|
print("Handler")
|
||||||
|
return {"message": "Hello from outer!"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def app_hello():
|
||||||
|
print("Handler")
|
||||||
|
return {"message": "Hello from app!"}
|
||||||
|
|
||||||
|
|
||||||
|
outer.include_router(inner)
|
||||||
|
app.include_router(outer)
|
||||||
|
|
@ -1084,6 +1084,7 @@ class FastAPI(Starlette):
|
||||||
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
|
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
|
||||||
generate_unique_id
|
generate_unique_id
|
||||||
),
|
),
|
||||||
|
middleware: Optional[List[Middleware]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.router.add_api_route(
|
self.router.add_api_route(
|
||||||
path,
|
path,
|
||||||
|
|
@ -1110,6 +1111,7 @@ class FastAPI(Starlette):
|
||||||
name=name,
|
name=name,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def api_route(
|
def api_route(
|
||||||
|
|
@ -1140,6 +1142,7 @@ class FastAPI(Starlette):
|
||||||
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
|
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
|
||||||
generate_unique_id
|
generate_unique_id
|
||||||
),
|
),
|
||||||
|
middleware: Optional[List[Middleware]] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||||
self.router.add_api_route(
|
self.router.add_api_route(
|
||||||
|
|
@ -1167,6 +1170,7 @@ class FastAPI(Starlette):
|
||||||
name=name,
|
name=name,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
@ -1788,6 +1792,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP GET operation.
|
Add a *path operation* using an HTTP GET operation.
|
||||||
|
|
@ -1828,6 +1847,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def put(
|
def put(
|
||||||
|
|
@ -2161,6 +2181,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP PUT operation.
|
Add a *path operation* using an HTTP PUT operation.
|
||||||
|
|
@ -2206,6 +2241,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(
|
def post(
|
||||||
|
|
@ -2539,6 +2575,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP POST operation.
|
Add a *path operation* using an HTTP POST operation.
|
||||||
|
|
@ -2584,6 +2635,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(
|
def delete(
|
||||||
|
|
@ -2917,6 +2969,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP DELETE operation.
|
Add a *path operation* using an HTTP DELETE operation.
|
||||||
|
|
@ -2957,6 +3024,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def options(
|
def options(
|
||||||
|
|
@ -3290,6 +3358,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP OPTIONS operation.
|
Add a *path operation* using an HTTP OPTIONS operation.
|
||||||
|
|
@ -3330,6 +3413,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def head(
|
def head(
|
||||||
|
|
@ -3663,6 +3747,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP HEAD operation.
|
Add a *path operation* using an HTTP HEAD operation.
|
||||||
|
|
@ -3703,6 +3802,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def patch(
|
def patch(
|
||||||
|
|
@ -4036,6 +4136,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP PATCH operation.
|
Add a *path operation* using an HTTP PATCH operation.
|
||||||
|
|
@ -4081,6 +4196,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def trace(
|
def trace(
|
||||||
|
|
@ -4414,6 +4530,21 @@ class FastAPI(Starlette):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP TRACE operation.
|
Add a *path operation* using an HTTP TRACE operation.
|
||||||
|
|
@ -4454,6 +4585,7 @@ class FastAPI(Starlette):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def websocket_route(
|
def websocket_route(
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ from pydantic import BaseModel
|
||||||
from starlette import routing
|
from starlette import routing
|
||||||
from starlette.concurrency import run_in_threadpool
|
from starlette.concurrency import run_in_threadpool
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
from starlette.middleware import Middleware
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.responses import JSONResponse, Response
|
from starlette.responses import JSONResponse, Response
|
||||||
from starlette.routing import (
|
from starlette.routing import (
|
||||||
|
|
@ -459,6 +460,7 @@ class APIRoute(routing.Route):
|
||||||
generate_unique_id_function: Union[
|
generate_unique_id_function: Union[
|
||||||
Callable[["APIRoute"], str], DefaultPlaceholder
|
Callable[["APIRoute"], str], DefaultPlaceholder
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Optional[Sequence[Middleware]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.path = path
|
self.path = path
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
|
|
@ -566,8 +568,13 @@ class APIRoute(routing.Route):
|
||||||
name=self.unique_id,
|
name=self.unique_id,
|
||||||
embed_body_fields=self._embed_body_fields,
|
embed_body_fields=self._embed_body_fields,
|
||||||
)
|
)
|
||||||
|
self.middleware = middleware
|
||||||
self.app = request_response(self.get_route_handler())
|
self.app = request_response(self.get_route_handler())
|
||||||
|
|
||||||
|
if middleware is not None:
|
||||||
|
for cls, args, kwargs in reversed(middleware):
|
||||||
|
self.app = cls(self.app, *args, **kwargs)
|
||||||
|
|
||||||
def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
|
def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
|
||||||
return get_request_handler(
|
return get_request_handler(
|
||||||
dependant=self.dependant,
|
dependant=self.dependant,
|
||||||
|
|
@ -833,6 +840,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this router.
|
||||||
|
|
||||||
|
Router-level middleware is executed after application-level middleware.
|
||||||
|
When multiple routers declare middleware, the outermost (furthest) router's middleware runs first.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(
|
super().__init__(
|
||||||
routes=routes,
|
routes=routes,
|
||||||
|
|
@ -841,6 +863,7 @@ class APIRouter(routing.Router):
|
||||||
on_startup=on_startup,
|
on_startup=on_startup,
|
||||||
on_shutdown=on_shutdown,
|
on_shutdown=on_shutdown,
|
||||||
lifespan=lifespan,
|
lifespan=lifespan,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
if prefix:
|
if prefix:
|
||||||
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
||||||
|
|
@ -858,6 +881,7 @@ class APIRouter(routing.Router):
|
||||||
self.route_class = route_class
|
self.route_class = route_class
|
||||||
self.default_response_class = default_response_class
|
self.default_response_class = default_response_class
|
||||||
self.generate_unique_id_function = generate_unique_id_function
|
self.generate_unique_id_function = generate_unique_id_function
|
||||||
|
self.middleware = middleware
|
||||||
|
|
||||||
def route(
|
def route(
|
||||||
self,
|
self,
|
||||||
|
|
@ -911,6 +935,7 @@ class APIRouter(routing.Router):
|
||||||
generate_unique_id_function: Union[
|
generate_unique_id_function: Union[
|
||||||
Callable[[APIRoute], str], DefaultPlaceholder
|
Callable[[APIRoute], str], DefaultPlaceholder
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Optional[List[Middleware]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
route_class = route_class_override or self.route_class
|
route_class = route_class_override or self.route_class
|
||||||
responses = responses or {}
|
responses = responses or {}
|
||||||
|
|
@ -930,6 +955,9 @@ class APIRouter(routing.Router):
|
||||||
current_generate_unique_id = get_value_or_default(
|
current_generate_unique_id = get_value_or_default(
|
||||||
generate_unique_id_function, self.generate_unique_id_function
|
generate_unique_id_function, self.generate_unique_id_function
|
||||||
)
|
)
|
||||||
|
if middleware and self.middleware:
|
||||||
|
middleware = self.middleware + middleware
|
||||||
|
|
||||||
route = route_class(
|
route = route_class(
|
||||||
self.prefix + path,
|
self.prefix + path,
|
||||||
endpoint=endpoint,
|
endpoint=endpoint,
|
||||||
|
|
@ -957,6 +985,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=current_callbacks,
|
callbacks=current_callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=current_generate_unique_id,
|
generate_unique_id_function=current_generate_unique_id,
|
||||||
|
middleware=middleware or self.middleware,
|
||||||
)
|
)
|
||||||
self.routes.append(route)
|
self.routes.append(route)
|
||||||
|
|
||||||
|
|
@ -989,6 +1018,7 @@ class APIRouter(routing.Router):
|
||||||
generate_unique_id_function: Callable[[APIRoute], str] = Default(
|
generate_unique_id_function: Callable[[APIRoute], str] = Default(
|
||||||
generate_unique_id
|
generate_unique_id
|
||||||
),
|
),
|
||||||
|
middleware: Optional[List[Middleware]] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||||
self.add_api_route(
|
self.add_api_route(
|
||||||
|
|
@ -1017,6 +1047,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
@ -1328,6 +1359,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=current_callbacks,
|
callbacks=current_callbacks,
|
||||||
openapi_extra=route.openapi_extra,
|
openapi_extra=route.openapi_extra,
|
||||||
generate_unique_id_function=current_generate_unique_id,
|
generate_unique_id_function=current_generate_unique_id,
|
||||||
|
middleware=route.middleware,
|
||||||
)
|
)
|
||||||
elif isinstance(route, routing.Route):
|
elif isinstance(route, routing.Route):
|
||||||
methods = list(route.methods or [])
|
methods = list(route.methods or [])
|
||||||
|
|
@ -1694,6 +1726,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP GET operation.
|
Add a *path operation* using an HTTP GET operation.
|
||||||
|
|
@ -1738,6 +1785,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def put(
|
def put(
|
||||||
|
|
@ -2071,6 +2119,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP PUT operation.
|
Add a *path operation* using an HTTP PUT operation.
|
||||||
|
|
@ -2120,6 +2183,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def post(
|
def post(
|
||||||
|
|
@ -2453,6 +2517,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP POST operation.
|
Add a *path operation* using an HTTP POST operation.
|
||||||
|
|
@ -2502,6 +2581,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete(
|
def delete(
|
||||||
|
|
@ -2835,6 +2915,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP DELETE operation.
|
Add a *path operation* using an HTTP DELETE operation.
|
||||||
|
|
@ -2879,6 +2974,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def options(
|
def options(
|
||||||
|
|
@ -3212,6 +3308,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP OPTIONS operation.
|
Add a *path operation* using an HTTP OPTIONS operation.
|
||||||
|
|
@ -3256,6 +3367,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def head(
|
def head(
|
||||||
|
|
@ -3589,6 +3701,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP HEAD operation.
|
Add a *path operation* using an HTTP HEAD operation.
|
||||||
|
|
@ -3638,6 +3765,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def patch(
|
def patch(
|
||||||
|
|
@ -3971,6 +4099,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP PATCH operation.
|
Add a *path operation* using an HTTP PATCH operation.
|
||||||
|
|
@ -4020,6 +4163,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
def trace(
|
def trace(
|
||||||
|
|
@ -4353,6 +4497,21 @@ class APIRouter(routing.Router):
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
] = Default(generate_unique_id),
|
] = Default(generate_unique_id),
|
||||||
|
middleware: Annotated[
|
||||||
|
Optional[Sequence[Middleware]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
List of middleware to apply to all requests handled by this route.
|
||||||
|
|
||||||
|
Route-level middleware is executed after application-level and router-level middleware.
|
||||||
|
Any middleware declared on the router will be called before this route's middleware.
|
||||||
|
Middleware are applied in reverse order: the last middleware in this list is the first to be called.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/)
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||||
"""
|
"""
|
||||||
Add a *path operation* using an HTTP TRACE operation.
|
Add a *path operation* using an HTTP TRACE operation.
|
||||||
|
|
@ -4402,6 +4561,7 @@ class APIRouter(routing.Router):
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
openapi_extra=openapi_extra,
|
openapi_extra=openapi_extra,
|
||||||
generate_unique_id_function=generate_unique_id_function,
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
middleware=middleware,
|
||||||
)
|
)
|
||||||
|
|
||||||
@deprecated(
|
@deprecated(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from docs_src.advanced_middleware.tutorial004 import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_middleware_called_once(capsys):
|
||||||
|
r = client.get("/")
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert captured.count("App before") == 1
|
||||||
|
assert captured.count("Outer before") == 0
|
||||||
|
assert captured.count("Handler") == 1
|
||||||
|
assert captured.count("Outer after") == 0
|
||||||
|
assert captured.count("App after") == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_outer_middleware_called_once(capsys):
|
||||||
|
r = client.get("/outer/")
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
assert captured.count("App before") == 1
|
||||||
|
assert captured.count("Outer before") == 1
|
||||||
|
assert captured.count("Handler") == 1
|
||||||
|
assert captured.count("Outer after") == 1
|
||||||
|
assert captured.count("App after") == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_name_middleware_called_once(capsys):
|
||||||
|
name = "you"
|
||||||
|
r = client.get(f"/outer/inner/{name}")
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert r.json() == {"message": f"Hello {name} from inner!"}
|
||||||
|
|
||||||
|
captured = capsys.readouterr().out
|
||||||
|
seq = [
|
||||||
|
"App before",
|
||||||
|
"Outer before",
|
||||||
|
f"Hi {name}!",
|
||||||
|
"Handler",
|
||||||
|
f"Bye {name}!",
|
||||||
|
"Outer after",
|
||||||
|
"App after",
|
||||||
|
]
|
||||||
|
for msg in seq:
|
||||||
|
assert captured.count(msg) == 1
|
||||||
|
|
||||||
|
idx = 0
|
||||||
|
for msg in seq:
|
||||||
|
next_idx = captured.find(msg, idx)
|
||||||
|
assert next_idx >= idx
|
||||||
|
idx = next_idx
|
||||||
Loading…
Reference in New Issue