FastAPI middlewares runs fantastically with ordinary requests, yet it might not execute background tasks.
It is a known issue that the BaseHTTPMiddleware
cannot be used with BackgroundTasks
.
(Read Limitations section in the doc)
However, FastAPI only guides solutions that using BaseHTTPMiddleware
class, by using app.middleware decorator like below.
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def some_middleware(request: Request, call_next):
# some logic here
return await call_next(request)
The decorator above uses BaseHTTPMiddleware under the hood, just like below:
# starlette/applications.py
def middleware(self, middleware_type: str) -> typing.Callable:
def decorator(func: typing.Callable) -> typing.Callable:
self.add_middleware(BaseHTTPMiddleware, dispatch=func)
return func
return decorator
In order to create a middleware but to guarantee execution of the background tasks, use pure middleware instead.
Pure Middleware
starlette docs introduces how to create a pure ASGI middleware.
In case creating a pure middleware with typing, example codes looks like below:
request_print_middleware.py
from starlette.types import ASGIApp, Scope, Receive, Send
from starlette.middleware import Middleware
class RequestPrintMiddleware:
"""Request Scope Print Middleware"""
def __init__(self, app: ASGIApp) -> None:
self.app = app
async def __call__(
self, scope: Scope, receive: Receive, send: Send
) -> None:
# Add logics here
print(scope)
await self.app(scope, receive, send)
Don’t forget to register the middleware.
main.py
from starlette.middleware import Middleware
middlewares = [Middleware(RequestPrintMiddleware)]
app = FastAPI(middleware=middlewares)
app.add_middleware
cannot be used, since Middleware cannot be asigned to the parameter middleware_class.
So you have to pass list of middlewares to middleware parameter, when you initiate app instance, just like the code provided above.