Way to customize error responses for `TypedHeader` in `axum-extras`
Closed this issue · 1 comments
- I have looked for existing issues (including closed) about this
Feature Request
Add a way to customize the error responses for TypedHeader
.
Motivation
Currently, failed TypedHeader
extractors always return code 400 with a plain text message. This works alright for many cases, but it may be more applicable to return a different error code, a JSON response, or a full 400 error page.
Proposal
My initial thought TypedHeader<T>
generic over an error type that implements From<TypedHeaderError>
and IntoResponse
, such as the below for the existing TypedHeaderRejection:
#[non_exhaustive]
pub struct TypedHeaderError<T> {
/// True if the header was present but incorrectly formed
pub is_present: bool,
/// The error created by the header extractor
pub error: headers::Error,
phantom: PhantomData<T>,
}
impl<T: Header> From<TypedHeaderError<T>> for TypedHeaderRejection {
fn from(value: TypedHeaderError<T>) -> Self {
Self {
name: T::name(),
reason: if value.is_present {
// Report a more precise rejection for the missing header case.
TypedHeaderRejectionReason::Missing
} else {
TypedHeaderRejectionReason::Error(value.error)
},
}
}
}
The problem with this is that the current TypedHeader<T>(pub T)
can't be made public over anything else without having a PhantomData field, which would break the API of function parameter destructuring like TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>
.
Alternatives
I don't know the best way to resolve the above issue outside of adding a new type. Const generics can be used without an extra PhantomData to customize only the error code:
#[derive(Debug)]
pub struct TypedHeader<T, const CODE: u16 = 400>(pub T);
#[derive(Debug)]
pub struct TypedHeaderRejection<const CODE: u16 = 400> {
name: &'static HeaderName,
reason: Reason,
}
// ...
impl<const CODE: u16> IntoResponse for TypedHeaderRejection<CODE> {
fn into_response(self) -> Response {
(StatusCode::from_u16(CODE).unwrap(), self.to_string()).into_response()
}
}
But that doesn't allow for setting a custom output type in any way.
You have some options now, the docs mention two:
- You can use a
Result<TypedHeader<T>, Error>
, but that also means you have to take the whole result as an argument and match it inside the handler (or a helper function) - Customize the error by wrapping it, see example, see there
with_rejection.rs
I think the second option here is what you're looking for?