-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement IntoResponse for Extension<T> #770
Comments
Just capturing my own thoughts here -- it looks like the approach used for the tuple type with headers won't work here. They implement
and
Ignoring the specifics of the implementation, I first tried doing something similar, defining an
and then attempt to implement for a tuple:
but this quite reasonably fails:
which makes sense, a type could implement both I'm definitely not familiar enough with the code base to say if this is a blocker. The only thing that immediately comes to mind is pulling
This does pass the complier, but that feels like a pretty major change for this feature. Its not immediately clear if it would be possible to move the definition of EDIT: Ok, one approach that might be a middle ground between "ideal ergonomics" and "major refactoring" is:
and
This allows for handlers like:
which isn't the worst by a long shot. But the possibly nicer
gives
Maybe something like
giving a handler of:
|
I might have been too attached to the idea of using the original extractor
Sorry for all the rambling, hopefully there's some value here somewhere! |
I think it might be possible to change |
Another thing to consider is that you cannot merge two |
With the anymap crate approaching 1.0 maybe http could switch to that in its next release. It looks like that one allows merging two maps via |
I've done some experiments now. To work around not being able to merge pub trait IntoResponseExtensions: Send + Sync + 'static {
fn into_extensions(self, extensions: &mut Extensions);
} Which we can the implement for tuples of different sizes. However you cannot implement a trait for // set status, one extension, and a body
(StatusCode::OK, Extension((extension,)), "Hello, World!") I quite dislike I'm not sure how to get around that with a consistent API. I mean one could imagine uses The fact that the extensions are different types is making this quite hard. With headers is easy stick things in an array because they're all the same type. I suppose a different solution would be changing pub trait IntoResponse {
fn into_response(self) -> Response;
fn with_extension<T>(self, extension: T) -> Response
where
T: Send + Sync + 'static,
Self: Sized,
{
let mut res = self.into_response();
res.extensions_mut().insert(extension);
res
}
} Usage would be async fn handler() -> Response {
Html("<h1>Hello, World!</h1>")
.with_extension(1)
.with_extension(2)
} It can be chained because @jplatte @Foleychris What do you think about this? |
As I was saying above, I think a good solution here could be to change |
Ah I missed that. Thats a great idea! I think #797 should do it! |
Sorry for going quiet on the issue, work ate up all my free time. With the caveat that I'm super junior to both Rust and Axum (so weigh my opinion accordingly!) I really like this new API from #797 on first read -- I'll definitely try to make some time to try it out this week. I'll be honest -- if I had thought implementing this would require reworking fundamental traits I probably wouldn't have opened this issue. I'm currently just using Axum for a toy app in a portfolio project. Using extensions in a response to interact with middleware made sense to me, but I definitely don't want to introduce any additional complexity to the project for my sake. If as maintainers this API makes sense to you, then I'm all in favor (and makes me think I'm starting to understand the ecosystem better 😄 ) |
Don't worry about it 😊 I think the fact that your (very reasonable) feature request couldn't be implemented previously showed that our fundamental abstractions weren't right. So we should fix them. |
The pattern of passing state into handlers via Request.extensions works very well across Axum, including passing state from middleware into a handler. Similarly, I would like to pass state back from a handler to a middleware. My thought was have Extension populate Response.extension, which could then be extracted in middleware, and combinations similar to
Headers
today.For a more concrete example, in the case of session handling today, individual handlers are required to handle session cookies (https://github.com/tokio-rs/axum/blob/main/examples/sessions/src/main.rs#L54-L58). With this approach, they could return
(StatusCode, Extension<User>)
from the handler, and the middleware would responsible for the cookie lifecycle end to end (extracting if present, setting if needed, etc).I would be willing to attempt the implementation of this, but may require some mentoring through the process.
EDIT: There's a long personal journey in this thread, but the tl;dr is in #770 (comment)
The text was updated successfully, but these errors were encountered: