I'd like to do a very simple task, that is add a middleware which runs before the endpoints and adds a few properties to the request object. Very similar to how authentication middleware does it, but I'd like to make it more flexible.
My aim is to have something like this:
Now, my problem is the following:
response = await call_next(request) and it adds a Header after the request has been processed. How can I use BaseHTTPMiddleware to add processing before an endpoint runs?INFO: ASGI 'lifespan' protocol appears unsupported. if I try to add something based on the skeleton of ProxyHeadersMiddleware. Will it disappear if I upgrade to 0.12.beta?BaseHTTPMiddleware in the docs starts with response = await call_next(request) and it adds a Header after the request has been processed. How can I use BaseHTTPMiddleware to add processing before an endpoint runs?
Processed by what?
Can I add custom properties to the request object in a Middleware?
Yes. To add custom props see: https://www.starlette.io/requests/#other-state
In case I cannot do it with BaseHTTPMiddleware I'm confused about the pure ASGI 2 vs. 3. middlewares. All the examples in starlette 0.11.4 are on ASGI 2, but ProxyHeadersMiddleware from uvicorn github is ASGI 3, do I understand it right?
ProxyHeadersMiddleware from uvicorn 0.6.1 is ASGI 2.
I get a INFO: ASGI 'lifespan' protocol appears unsupported.
Make sure, that "startup" lifespan event does not throw exceptions.
Processed by what?
By the view / endpoint function. What is not clear is how to write middlewares in B.. (for before) and A.. (for after) states in the following diagram.
HTTP Request -> B1 -> B2 -> B3 -> view function -> A1 -> A2 -> A3 -> HTTP Response
For example, the ProxyHeadersMiddleware would be in a B place here, as it adds information to the request before it reaches the view function. The add_custom_header example would be in place A, as it adds a header to the response, after it has been processed by the view function.
ProxyHeadersMiddleware from uvicorn 0.6.1 is ASGI 2.
I understand now. The linked file in the docs points to master branch, which is on ASGI 3, but the pip installed version is still on ASGI 2.
Make sure, that "startup" lifespan event does not throw exceptions.
There is nothing in there, I'm just adding a blank middleware skeleton, this one:
class ASGIMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
await self.app(scope, receive, send)
The moment I add this it throws a INFO: ASGI 'lifespan' protocol appears unsupported. log line.
I just tested upgrading to 0.12.0.b3 and the ASGI 'lifespan' protocol appears unsupported is now gone.
OK, I've been able to make some progress trying to write my ASGI middleware for 0.12.
class JSONAuthMiddleware:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
if scope['type'] != 'http':
response = PlainTextResponse('non http', status_code=400)
await response(scope, receive, send)
if scope['method'] != 'POST':
response = PlainTextResponse('non POST', status_code=400)
await response(scope, receive, send)
request = Request(scope, receive=receive)
data = await request.json()
await self.app(scope, receive, send)
My problem is that if I add a request.json() line in the middleware, then it cannot be called in the view. When the view calls it, it stalls the app and uvicorn need to be force quitted (Waiting for connections to close. (CTRL+C to force quit)).
How can I solve this (or maybe this is a bug?).
The problem seems to be that request._body and request._json disappears between the middleware and the view and then the flow is locked at stream(). Also, because everything disappears from the request, not even the RuntimeError("Stream consumed") is thrown (although it wouldn't help me).
If you'd like I can make a small reproducible use case for this.
There's a bunch of different things being asked here, so I'm going to close this off as a general discussion rather than a narrowed-down actionable requested change.
Most helpful comment
OK, I've been able to make some progress trying to write my ASGI middleware for 0.12.
My problem is that if I add a
request.json()line in the middleware, then it cannot be called in the view. When the view calls it, it stalls the app and uvicorn need to be force quitted (Waiting for connections to close. (CTRL+C to force quit)).How can I solve this (or maybe this is a bug?).