-
Notifications
You must be signed in to change notification settings - Fork 3
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
Add axum support #30
base: main
Are you sure you want to change the base?
Add axum support #30
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice PR!
I have a few comments that all come down to the same thing; we're not generic enough on the error type.
You can see it easily if you try to return a QueryParamError
in the deserr
example like that;
async fn deserr(item: AxumJson<Query, QueryParamError>) -> AxumJson<Query, QueryParamError> {
item
}
This should work without requiring the user to implement anything specific I think 🤔
@@ -2,8 +2,7 @@ | |||
name = "actix_web_server" | |||
version = "0.1.0" | |||
edition = "2021" | |||
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |||
publish = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
@@ -2,6 +2,8 @@ | |||
|
|||
#[cfg(feature = "actix-web")] | |||
pub mod actix_web; | |||
// #[cfg(feature = "axum")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be commented 😁
// #[cfg(feature = "axum")] | |
#[cfg(feature = "axum")] |
} | ||
} | ||
|
||
/// This handler uses the official `AxumJson` deserr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This handler uses the official `AxumJson` deserr | |
/// This handler uses the official `AxumJson` deserr extractor |
#[derive(Debug)] | ||
pub enum AxumJsonRejection { | ||
DeserrError(JsonError), | ||
JsonRejection(JsonRejection), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should let the end user decide which kind of error they want to return.
#[derive(Debug)] | |
pub enum AxumJsonRejection { | |
DeserrError(JsonError), | |
JsonRejection(JsonRejection), | |
} | |
#[derive(Debug)] | |
pub enum AxumJsonRejection<E: DeserializeError> { | |
DeserrError(E), | |
JsonRejection(JsonRejection), | |
} |
#[async_trait] | ||
impl<T, S, B, E: DeserializeError> FromRequest<S, B> for AxumJson<T, E> | ||
where | ||
T: Deserr<E>, | ||
E: DeserializeError + 'static, | ||
B: HttpBody + Send + 'static, | ||
B::Data: Send, | ||
B::Error: Into<BoxError>, | ||
S: Send + Sync, | ||
AxumJsonRejection: std::convert::From<E>, | ||
{ | ||
type Rejection = AxumJsonRejection; | ||
|
||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { | ||
let Json(value): Json<serde_json::Value> = Json::from_request(req, state).await?; | ||
let data = deserr::deserialize::<_, _, _>(value)?; | ||
Ok(AxumJson(data, PhantomData)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[async_trait] | |
impl<T, S, B, E: DeserializeError> FromRequest<S, B> for AxumJson<T, E> | |
where | |
T: Deserr<E>, | |
E: DeserializeError + 'static, | |
B: HttpBody + Send + 'static, | |
B::Data: Send, | |
B::Error: Into<BoxError>, | |
S: Send + Sync, | |
AxumJsonRejection: std::convert::From<E>, | |
{ | |
type Rejection = AxumJsonRejection; | |
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { | |
let Json(value): Json<serde_json::Value> = Json::from_request(req, state).await?; | |
let data = deserr::deserialize::<_, _, _>(value)?; | |
Ok(AxumJson(data, PhantomData)) | |
} | |
} | |
#[async_trait] | |
impl<T, S, B, E: DeserializeError> FromRequest<S, B> for AxumJson<T, E> | |
where | |
T: Deserr<E>, | |
E: DeserializeError + 'static, | |
B: HttpBody + Send + 'static, | |
B::Data: Send, | |
B::Error: Into<BoxError>, | |
S: Send + Sync, | |
{ | |
type Rejection = AxumJsonRejection<E>; | |
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { | |
let Json(value): Json<serde_json::Value> = Json::from_request(req, state).await?; | |
let data = deserr::deserialize::<_, _, _>(value)?; | |
Ok(AxumJson(data, PhantomData)) | |
} | |
} |
impl From<JsonError> for AxumJsonRejection { | ||
fn from(value: JsonError) -> Self { | ||
AxumJsonRejection::DeserrError(value) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
impl From<JsonError> for AxumJsonRejection { | |
fn from(value: JsonError) -> Self { | |
AxumJsonRejection::DeserrError(value) | |
} | |
} |
I don't think we can keep this while being fully generic over the error type.
impl IntoResponse for AxumJsonRejection { | ||
fn into_response(self) -> axum::response::Response { | ||
match self { | ||
AxumJsonRejection::DeserrError(e) => e.into_response(), | ||
AxumJsonRejection::JsonRejection(e) => e.into_response(), | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe in the previous comments, we were supposed to also constraint E
to implement IntoResponse
?
impl IntoResponse for JsonError { | ||
fn into_response(self) -> axum::response::Response { | ||
(StatusCode::BAD_REQUEST, self.to_string()).into_response() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice though, it will help someone who don't want to use his own error type 👍
What does this PR do?
This PR add deserr support for axum via the
AxumJson
wrapper type.Note that unlike the actix-web feature serde is needed to provide a
axum::IntoResponse
blanquet implementation forT: serde::Serialize
.Misc