I have a custom IntoResponse type that needs to return different data to the client depending on the value of the Accept header in the request. I would prefer, if possible, to have this be seamless (i.e. I don't have to pass the header value into the IntoResponse type's constructor). I thought the most straightforward way to accomplish this would be to write a layer using Axum's middleware system that all functions returning that type are required to be wrapped with, not have the type implement IntoResponse, and instead perform the conversion inside the middleware so that it could access the request headers, but it seems that Axum's middleware system requires the service function to return an IntoResponse. Could I whip something up with a tower::Layer that does the same thing?
Get access to the request headers from Axum IntoResponse
3.2k views Asked by wallefan At
1
Firstly, lets get it out of the way that there is not a built-in mechanism to support the
Acceptheader impacting the response. See this brief discussion.You've probably noticed the
IntoResponsetrait that handlers must yield does not provide access to the original request:So you'd have to get the header from either the handler itself or some middleware.
Even worse, it requires the body be a sequence of bytes (which makes sense but loses type information). So a middleware would have to decode data from the encoded response body to modify it for a different mime type. This could probably work if your data is really simple, but for a lot of cases this would probably be an annoying and unnecessary cost. This data flow also impacts how underlying
towerservices can affect the response, so the distinction doesn't help.Fortunately, there is another way: you can provide any data to your middleware via an
Extension. Through.extensions()/.extensions_mut()on a response, you can store arbitrary data, so yourIntoResponseimplementation can store itself in an extension that a middeware could then pull out and re-format as necessary.Here's a mockup of how that could work: