Skip to content
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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Add axum support #30

wants to merge 2 commits into from

Conversation

oknozor
Copy link

@oknozor oknozor commented Feb 2, 2023

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 for T: serde::Serialize.

Misc

  • Added crates.io and doc.rs badges on the README

Copy link
Member

@irevoire irevoire left a 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
Copy link
Member

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")]
Copy link
Member

@irevoire irevoire Feb 2, 2023

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 😁

Suggested change
// #[cfg(feature = "axum")]
#[cfg(feature = "axum")]

}
}

/// This handler uses the official `AxumJson` deserr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// This handler uses the official `AxumJson` deserr
/// This handler uses the official `AxumJson` deserr extractor

Comment on lines +25 to +29
#[derive(Debug)]
pub enum AxumJsonRejection {
DeserrError(JsonError),
JsonRejection(JsonRejection),
}
Copy link
Member

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.

Suggested change
#[derive(Debug)]
pub enum AxumJsonRejection {
DeserrError(JsonError),
JsonRejection(JsonRejection),
}
#[derive(Debug)]
pub enum AxumJsonRejection<E: DeserializeError> {
DeserrError(E),
JsonRejection(JsonRejection),
}

Comment on lines +40 to +58
#[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))
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[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))
}
}

Comment on lines +60 to +64
impl From<JsonError> for AxumJsonRejection {
fn from(value: JsonError) -> Self {
AxumJsonRejection::DeserrError(value)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Comment on lines +72 to +79
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(),
}
}
}
Copy link
Member

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?

Comment on lines +81 to +85
impl IntoResponse for JsonError {
fn into_response(self) -> axum::response::Response {
(StatusCode::BAD_REQUEST, self.to_string()).into_response()
}
}
Copy link
Member

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 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants