axum icon indicating copy to clipboard operation
axum copied to clipboard

Fix `IntoResponse` for tuples overriding error response codes

Open davidpdrsn opened this issue 1 year ago • 5 comments

Fixes https://github.com/tokio-rs/axum/issues/2287

I think 3rd option is the way to go. If we went with option 2 then things like

(StatusCode::SEE_OTHER, [("location", "...")], StatusCode::INTERNAL_SERVER_ERROR).into_response()

would have to skip the IntoResponseParts in the middle as well as StatusCode::SEE_OTHER, otherwise we'd get a 500 with a location header.

However we probably shouldn't skip the IntoResponseParts if the first element isn't a status code

(Extension(error_that_happened), StatusCode::INTERNAL_SERVER_ERROR).into_response()

That feels somewhat inconsistent and combined with the fact that it might break middleware that "catch errors" and use tuples to construct new responses I think adding a specific extension to signal "IntoResponse failed" is nicer.

So this PR does just that. It adds IntoResponseFailed which if present in response extensions makes other response transformations not run. Thus the 500 status code of

(StatusCode::CREATED, Json::<NotJsonCompatible>(...))

is maintained.

TODO

  • [x] Audit our IntoResponse and IntoResponseParts impls and add IntoResponseFailed where necessary.
  • [ ] Make sure you can still write middleware that catch and transforms errors.
  • [x] Provide OverrideAllStatusCodes(StatusCode) newtype to opt-out and always set the status code.
  • [ ] Changelog

davidpdrsn avatar Dec 30 '23 16:12 davidpdrsn

Looks decent, but I'm wondering if we should ship this in 0.7.x. It seems pretty likely that some people are relying on IntoResponseParts from a tuple running even if the final tuple element produces an error (e.g. headers used for distributed tracing).

Yeah we probably should wait for 0.8.

Also, re. OverrideAllStatusCodes, could ForceStatusCode be a better name? It's a bit shorter.

👍

davidpdrsn avatar Dec 30 '23 18:12 davidpdrsn

Do you think we should ship 0.8 soon / start planning for what should be part of it? The async-trait removal is another big breaking change, plus potentially requiring Sync for inner services (or something along those lines, I have some other ideas in that area). Those changes seem large enough to warrant another breaking release, though there might be other things we should wait for (e.g. another matchit release since the routing syntax is changing).

jplatte avatar Dec 30 '23 18:12 jplatte

Yeah I think we should ship sooner rather than later. We'll probably get some hype from being the first major framework to adopt AFIT 😅 although coordinating with matchit would be good.

davidpdrsn avatar Dec 30 '23 18:12 davidpdrsn

@jplatte I've fixed the merge conflicts from main and fixed the compilation errors. Do you think it makes sense to spend time on this? Is it the right direction?

yanns avatar Nov 30 '24 14:11 yanns

I still think this is probably the right direction, but am pretty swamped with life right now. The associated issue is part of the 0.9 milestone, I think that should help me find this again pretty quickly once I go from my current reactive only-look-at-notifications mode to something more proactive where I revisit the open tasks.

jplatte avatar Jan 28 '25 23:01 jplatte