connexion icon indicating copy to clipboard operation
connexion copied to clipboard

Update context throughout middleware stack?

Open RobbeSneyders opened this issue 2 years ago • 5 comments

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

RobbeSneyders avatar Oct 22 '23 20:10 RobbeSneyders

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.

SpudInNZ avatar Nov 01 '23 19:11 SpudInNZ

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.

explody avatar Nov 09 '23 06:11 explody

@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.

chbndrhnns avatar Feb 06 '24 17:02 chbndrhnns

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

pradhan-v avatar Aug 14 '24 19:08 pradhan-v