From 7e13d696395a4cf61bd1bb4fcf453630a564656b Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 2 Dec 2022 19:54:16 +0100 Subject: [PATCH] Add `status` and `body_text` methods to built-in rejections (#1612) * Add `status` and `body_text` methods to built-in rejections This should make it easier to customize a built-in rejection while preserving either the status or body. Fixes https://github.com/tokio-rs/axum/issues/1611 * changelog --- axum-core/CHANGELOG.md | 4 ++- axum-core/src/macros.rs | 37 +++++++++++++++++++++++--- axum/CHANGELOG.md | 4 ++- axum/src/extract/path/mod.rs | 37 ++++++++++++++++++-------- axum/src/macros.rs | 51 ++++++++++++++++++++++++++++++++---- 5 files changed, 111 insertions(+), 22 deletions(-) diff --git a/axum-core/CHANGELOG.md b/axum-core/CHANGELOG.md index f46ad4cb..c9161c8b 100644 --- a/axum-core/CHANGELOG.md +++ b/axum-core/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased -- None. +- **added:** Add `body_text` and `status` methods to built-in rejections ([#1612]) + +[#1612]: https://github.com/tokio-rs/axum/pull/1612 # 0.3.0 (25. November, 2022) diff --git a/axum-core/src/macros.rs b/axum-core/src/macros.rs index 779bb719..a82f3bbd 100644 --- a/axum-core/src/macros.rs +++ b/axum-core/src/macros.rs @@ -19,12 +19,21 @@ macro_rules! define_rejection { } } + impl $name { + /// Get the response body text used for this rejection. + pub fn body_text(&self) -> String { + format!(concat!($body, ": {}"), self.0).into() + } + + /// Get the status code used for this rejection. + pub fn status(&self) -> http::StatusCode { + http::StatusCode::$status + } + } + impl crate::response::IntoResponse for $name { fn into_response(self) -> $crate::response::Response { - ( - http::StatusCode::$status, - format!(concat!($body, ": {}"), self.0) - ).into_response() + (self.status(), self.body_text()).into_response() } } @@ -70,6 +79,26 @@ macro_rules! composite_rejection { } } + impl $name { + /// Get the response body text used for this rejection. + pub fn body_text(&self) -> String { + match self { + $( + Self::$variant(inner) => inner.body_text(), + )+ + } + } + + /// Get the status code used for this rejection. + pub fn status(&self) -> http::StatusCode { + match self { + $( + Self::$variant(inner) => inner.status(), + )+ + } + } + } + $( impl From<$variant> for $name { fn from(inner: $variant) -> Self { diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 706f5abe..0c135524 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased -- None. +- **added:** Add `body_text` and `status` methods to built-in rejections ([#1612]) + +[#1612]: https://github.com/tokio-rs/axum/pull/1612 # 0.6.1 (29. November, 2022) diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs index ad4e5eb4..a5a239af 100644 --- a/axum/src/extract/path/mod.rs +++ b/axum/src/extract/path/mod.rs @@ -383,24 +383,39 @@ impl FailedToDeserializePathParams { pub fn into_kind(self) -> ErrorKind { self.0.kind } -} -impl IntoResponse for FailedToDeserializePathParams { - fn into_response(self) -> Response { - let (status, body) = match self.0.kind { + /// Get the response body text used for this rejection. + pub fn body_text(&self) -> String { + match self.0.kind { ErrorKind::Message(_) | ErrorKind::InvalidUtf8InPathParam { .. } | ErrorKind::ParseError { .. } | ErrorKind::ParseErrorAtIndex { .. } - | ErrorKind::ParseErrorAtKey { .. } => ( - StatusCode::BAD_REQUEST, - format!("Invalid URL: {}", self.0.kind), - ), + | ErrorKind::ParseErrorAtKey { .. } => format!("Invalid URL: {}", self.0.kind), ErrorKind::WrongNumberOfParameters { .. } | ErrorKind::UnsupportedType { .. } => { - (StatusCode::INTERNAL_SERVER_ERROR, self.0.kind.to_string()) + self.0.kind.to_string() } - }; - (status, body).into_response() + } + } + + /// Get the status code used for this rejection. + pub fn status(&self) -> StatusCode { + match self.0.kind { + ErrorKind::Message(_) + | ErrorKind::InvalidUtf8InPathParam { .. } + | ErrorKind::ParseError { .. } + | ErrorKind::ParseErrorAtIndex { .. } + | ErrorKind::ParseErrorAtKey { .. } => StatusCode::BAD_REQUEST, + ErrorKind::WrongNumberOfParameters { .. } | ErrorKind::UnsupportedType { .. } => { + StatusCode::INTERNAL_SERVER_ERROR + } + } + } +} + +impl IntoResponse for FailedToDeserializePathParams { + fn into_response(self) -> Response { + (self.status(), self.body_text()).into_response() } } diff --git a/axum/src/macros.rs b/axum/src/macros.rs index 54600e01..abff1dd7 100644 --- a/axum/src/macros.rs +++ b/axum/src/macros.rs @@ -59,7 +59,19 @@ macro_rules! define_rejection { impl $crate::response::IntoResponse for $name { fn into_response(self) -> $crate::response::Response { - (http::StatusCode::$status, $body).into_response() + (self.status(), $body).into_response() + } + } + + impl $name { + /// Get the response body text used for this rejection. + pub fn body_text(&self) -> String { + $body.into() + } + + /// Get the status code used for this rejection. + pub fn status(&self) -> http::StatusCode { + http::StatusCode::$status } } @@ -99,10 +111,19 @@ macro_rules! define_rejection { impl crate::response::IntoResponse for $name { fn into_response(self) -> $crate::response::Response { - ( - http::StatusCode::$status, - format!(concat!($body, ": {}"), self.0), - ).into_response() + (self.status(), self.body_text()).into_response() + } + } + + impl $name { + /// Get the response body text used for this rejection. + pub fn body_text(&self) -> String { + format!(concat!($body, ": {}"), self.0).into() + } + + /// Get the status code used for this rejection. + pub fn status(&self) -> http::StatusCode { + http::StatusCode::$status } } @@ -148,6 +169,26 @@ macro_rules! composite_rejection { } } + impl $name { + /// Get the response body text used for this rejection. + pub fn body_text(&self) -> String { + match self { + $( + Self::$variant(inner) => inner.body_text(), + )+ + } + } + + /// Get the status code used for this rejection. + pub fn status(&self) -> http::StatusCode { + match self { + $( + Self::$variant(inner) => inner.status(), + )+ + } + } + } + $( impl From<$variant> for $name { fn from(inner: $variant) -> Self {