tokio-rs / axum

Ergonomic and modular web framework built with Tokio, Tower, and Hyper

Repository from Github https://github.comtokio-rs/axumRepository from Github https://github.comtokio-rs/axum

Make `Redirect` testable

MidasLamb opened this issue · comments

  • I have looked for existing issues (including closed) about this

Feature Request

Motivation

One of the advantages of axum is that the handlers (can) return strongly typed values, that get turned into HTTP later down the line, this means you can write unit tests that don't have to reinterpret the HTTP to see if the inner logic was correct.
However, when writing tests for something that returns a Redirect, there was no way of inspecting the Redirect once constructed (without relying on IntoResponse)

Proposal

Rework Redirect to not have status code internally, but rather be an enum (or contain an enum) and move the "status code" logic

pub fn to(uri: &str) -> Self {
Self::with_status_code(StatusCode::SEE_OTHER, uri)
}

into the IntoResponse implementation

impl IntoResponse for Redirect {
fn into_response(self) -> Response {
(self.status_code, [(LOCATION, self.location)]).into_response()
}
}

With this, we can add introspection methods easily (is_to(), location()).

I do think that this approach would also be more in line with the philosophy of axum about how the IntoResponse trait is meant to be used (but I might be wrong here) .

I'd be glad to put up a PR for this, but I'd thought a discussion around it first would be fitting.

Alternatives

Keep the logic as is, but add introspection that "reverses" the initial logic (i.e. StatusCode::TEMPORARY_REDIRECT means it was constructed with the temporary function.

How about adding just status_code and location methods?

commented

I've drafted a PR at #3377. We could also consider reworking the Redirect so the URI is stored in the Redirect as a &str, and only makes a header at IntoResponse, or make it a enum as mentioned.

For now I only added a location() which returns a parsed to_str() result of the HeaderValue, and a status_code() which returns the current status code without rework of the structure. I also added some tests which all run successfully.

commented

Also wouldn't making Redirect contain a &str as the URI and making it a enum make it so that we can guarantee the Redirect is valid and Result's aren't required in the internal Redirect? Could also .expect on the location()as it's impossible to not be UTF-8, and these changes would be a breaking change, but a big plus to safety too.

commented

Believe this issue got resolved in #3377, and can be closed now. 👍