Wanted to provide an updated answer here. My original comment is on a starlette issue, here.
I am using FastAPI, and needed a way to access information on the request object outside of a view. I initially looked at using starlette-context but found the below solution to work for my needs.
Credit to Marc (see starlette issue above) for the basis of this solution.
As noted by Colin Le Nost above, the authors warn against using BaseHTTPMiddleware
-- the parent class Marc's middleware inherits from.
Instead, the suggestion is to use a raw ASGI middleware. However, there isn't much documentation for this. I was able to use Starlette's AuthenticationMiddleware as a reference point, and develop what I needed in combination with Marc's wonderful solution of ContextVars.
# middleware.py
from starlette.types import ASGIApp, Receive, Scope, Send
REQUEST_ID_CTX_KEY = "request_id"
_request_id_ctx_var: ContextVar[str] = ContextVar(REQUEST_ID_CTX_KEY, default=None)
def get_request_id() -> str:
return _request_id_ctx_var.get()
class CustomRequestMiddleware:
def __init__(
self,
app: ASGIApp,
) -> None:
self.app = app
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope["type"] not in ["http", "websocket"]:
await self.app(scope, receive, send)
return
request_id = _request_id_ctx_var.set(str(uuid4()))
await self.app(scope, receive, send)
_request_id_ctx_var.reset(request_id)
And then in the app setup:
# main.py
app.add_middleware(CustomRequestMiddleware)
And finally, the non-view function:
# myfunc.py
import get_request_id
request_id = get_request_id()
This should enable you to use ContextVars as a way to get any info from the request object you need, and make it available outside of view function. Thanks again to everyone in this thread for all the help, and I hope the above is useful!