From 0c7ff7c76bb3aba7b9b4fad05b37f9481d2cd619 Mon Sep 17 00:00:00 2001 From: wayne Date: Sat, 18 Nov 2023 12:29:57 +0000 Subject: [PATCH] Json: add from_bytes method, use that in 'impl FromRequest' (#2244) Signed-off-by: wayne warren Co-authored-by: Jonas Platte --- axum/CHANGELOG.md | 2 ++ axum/src/json.rs | 62 ++++++++++++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 7294549c..af55ff27 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -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 @@ -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) diff --git a/axum/src/json.rs b/axum/src/json.rs index 74541c1e..ebff242d 100644 --- a/axum/src/json.rs +++ b/axum/src/json.rs @@ -103,31 +103,7 @@ where async fn from_request(req: Request, state: &S) -> Result { 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()) } @@ -167,6 +143,42 @@ impl From for Json { } } +impl Json +where + T: DeserializeOwned, +{ + /// Construct a `Json` 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`. + pub fn from_bytes(bytes: &[u8]) -> Result { + 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 IntoResponse for Json where T: Serialize,