Update context throughout middleware stack?
We currently set the Context variables offered to the user in the ContextMiddleware at the end of the stack, which makes them available in view functions and any code called from there.
In code called earlier in the middleware stack, such as the security functions for example, the context is not available.
Each middleware has access to all the information needed to set the context, so we could update the context in each middleware throughout the middleware stack to make it accessible to code running anywhere in the stack during a request.
Note that middlewares handling responses, such as the ResponseValidation, actually need this context when returning the response, so we might have to set and unset it as follows:
def __call__(self, scope, receive, send):
# Set context variables
# Logic working on requests
# Unset context variables
self.next_app(scope, receive, send)
# Set context variables
# Logic working on responses
# Unset context variables
Big +1 for this. This issue bit me quite hard when we were trying to move from a non-trivial Connexion 2 codebase to 3. I can't recall the workaround we had to do, but it wasn't pretty.
Another big +1 on this. I'm working on a custom authentication scenario that needs access to the request context, to make authn and authz decisions based on data in the request.
@SpudInNZ May I ask for your workaround? I need access to the request in the security middleware and currently I have no idea how to do that.
For middlewares inheriting the starlette.middleware.base.BaseHTTPMiddleware the context and the request object can be accessed with this workaround
from starlette.middleware.base import BaseHTTPMiddleware
class RequestIdMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
request_id = request.headers.get("x-request-id")
# FIXME: https://github.com/spec-first/connexion/issues/1750
connexion_context = request.scope.get("extensions", {}).get("connexion_context", {})
connexion_context["request_id"] = request_id
response = await call_next(request)
response.headers["request_id"] = request_id
return response