Skip to content

Commit

Permalink
Json: add from_bytes method, use that in 'impl FromRequest' (#2244)
Browse files Browse the repository at this point in the history
Signed-off-by: wayne warren <[email protected]>
Co-authored-by: Jonas Platte <[email protected]>
  • Loading branch information
waynr and jplatte authored Nov 18, 2023
1 parent c100650 commit 0c7ff7c
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 25 deletions.
2 changes: 2 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **added:** Implement `IntoResponse` for `(R,) where R: IntoResponse` ([#2143])
- **changed:** For SSE, add space between field and value for compatibility ([#2149])
- **added:** Add `NestedPath` extractor ([#1924])
- **added:** Add `axum::Json::from_bytes` ([#2244])

[#1664]: https://github.com/tokio-rs/axum/pull/1664
[#1751]: https://github.com/tokio-rs/axum/pull/1751
Expand All @@ -86,6 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#2140]: https://github.com/tokio-rs/axum/pull/2140
[#2143]: https://github.com/tokio-rs/axum/pull/2143
[#2149]: https://github.com/tokio-rs/axum/pull/2149
[#2244]: https://github.com/tokio-rs/axum/pull/2244

# 0.6.17 (25. April, 2023)

Expand Down
62 changes: 37 additions & 25 deletions axum/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,31 +103,7 @@ where
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
if json_content_type(req.headers()) {
let bytes = Bytes::from_request(req, state).await?;
let deserializer = &mut serde_json::Deserializer::from_slice(&bytes);

let value = match serde_path_to_error::deserialize(deserializer) {
Ok(value) => value,
Err(err) => {
let rejection = match err.inner().classify() {
serde_json::error::Category::Data => JsonDataError::from_err(err).into(),
serde_json::error::Category::Syntax | serde_json::error::Category::Eof => {
JsonSyntaxError::from_err(err).into()
}
serde_json::error::Category::Io => {
if cfg!(debug_assertions) {
// we don't use `serde_json::from_reader` and instead always buffer
// bodies first, so we shouldn't encounter any IO errors
unreachable!()
} else {
JsonSyntaxError::from_err(err).into()
}
}
};
return Err(rejection);
}
};

Ok(Json(value))
Self::from_bytes(&bytes)
} else {
Err(MissingJsonContentType.into())
}
Expand Down Expand Up @@ -167,6 +143,42 @@ impl<T> From<T> for Json<T> {
}
}

impl<T> Json<T>
where
T: DeserializeOwned,
{
/// Construct a `Json<T>` from a byte slice. Most users should prefer to use the `FromRequest` impl
/// but special cases may require first extracting a `Request` into `Bytes` then optionally
/// constructing a `Json<T>`.
pub fn from_bytes(bytes: &[u8]) -> Result<Self, JsonRejection> {
let deserializer = &mut serde_json::Deserializer::from_slice(bytes);

let value = match serde_path_to_error::deserialize(deserializer) {
Ok(value) => value,
Err(err) => {
let rejection = match err.inner().classify() {
serde_json::error::Category::Data => JsonDataError::from_err(err).into(),
serde_json::error::Category::Syntax | serde_json::error::Category::Eof => {
JsonSyntaxError::from_err(err).into()
}
serde_json::error::Category::Io => {
if cfg!(debug_assertions) {
// we don't use `serde_json::from_reader` and instead always buffer
// bodies first, so we shouldn't encounter any IO errors
unreachable!()
} else {
JsonSyntaxError::from_err(err).into()
}
}
};
return Err(rejection);
}
};

Ok(Json(value))
}
}

impl<T> IntoResponse for Json<T>
where
T: Serialize,
Expand Down

0 comments on commit 0c7ff7c

Please sign in to comment.