Middleware
What for
The middleware effectively creates the context for the request, so you must configure your app to use it. More usage detail along with code examples can be found in Plugins.
Errors and Middlewares in Starlette
There may be a validation error occuring while processing the request in the plugins, which requires sending an error response. Starlette however does not let middleware use the regular error handler (more details), so middlewares facing a validation error have to send a response by themselves.
By default, the response sent will be a 400 with no body or extra header, as a Starlette Response(status_code=400)
.
This response can be customized at both middleware and plugin level.
The middlewares accepts a Response
object (or anything that inherits it, such as a JSONResponse
) through default_error_response
keyword argument at init.
This response will be sent on raised starlette_context.errors.MiddleWareValidationError
exceptions, if it doesn’t include a response itself.
middleware = [
Middleware(
ContextMiddleware,
default_error_response=JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
content={"Error": "Invalid request"},
),
# plugins = ...
)
]
Why are there two middlewares that do the same thing
Warning
ContextMiddleware
middleware is deprecated and will be removed in version 1.0.0.
Use RawContextMiddleware
instead. For more information, see
this ticket.
ContextMiddleware
inherits from BaseHTTPMiddleware
which is an interface prepared by encode
.
That is, in theory, the “normal” way of creating a middleware. It’s simple and convenient.
However, if you are using StreamingResponse
, you might bump into memory issues. See
Authors recently started to discourage the use of BaseHTTPMiddleware in favor of what they call “raw middleware”. The problem with the “raw” one is that there’s no docs for how to actually create it.
The RawContextMiddleware
does more or less the same thing.
It is entirely possible that ContextMiddleware
will be removed in the future release.
It is also possible that authors will make some changes to the BaseHTTPMiddleware
to fix this issue.
I’d advise to only use RawContextMiddleware
.
Warning
Due to how Starlette handles application exceptions, the enrich_response
method won’t run,
and the default error response will not be used after an unhandled exception.
Therefore, this middleware is not capable of setting response headers for 500 responses. You can try to use your own 500 handler, but beware that the context will not be available.
How does it work
First, an empty “storage” is created, that’s bound to the context of your async request.
The set_context
method allows you to assign something to the context on creation
therefore that’s the best place to add everything that might come in
handy later on. You can always alter the context, so add/remove items from it, but each operation comes with some cost.
All plugins
are executed when set_context
method is called. If you want to add something else there you might
either write your own plugin or just overwrite the set_context
method which returns a dict
.
Then, once the response is created, we iterate over plugins so it’s possible to set some response headers based on the context contents.
Finally, the “storage” that async python apps can access is removed.