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
(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.
starlette docs introduces how to create a pure ASGI middleware.
In case creating a pure middleware with typing, example codes looks like below:
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.
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.