From edd4e7b661174c1a1d808d95c313d8b7f5764c11 Mon Sep 17 00:00:00 2001 From: Altair-Bueno <67512202+Altair-Bueno@users.noreply.github.com> Date: Thu, 18 Aug 2022 20:41:26 +0200 Subject: [PATCH] examples(error-handling): `derive_from_request` --- examples/error-handling/Cargo.toml | 1 + .../error-handling/src/derive_from_request.rs | 46 +++++++++++++++++++ examples/error-handling/src/main.rs | 6 ++- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 examples/error-handling/src/derive_from_request.rs diff --git a/examples/error-handling/Cargo.toml b/examples/error-handling/Cargo.toml index f090d579..326febbc 100644 --- a/examples/error-handling/Cargo.toml +++ b/examples/error-handling/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] axum = { path = "../../axum", features=["matched-path"] } axum-extra = { path = "../../axum-extra" } +axum-macros = { path = "../../axum-macros" } chrono = { version = "0.4", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/examples/error-handling/src/derive_from_request.rs b/examples/error-handling/src/derive_from_request.rs new file mode 100644 index 00000000..5d6da96d --- /dev/null +++ b/examples/error-handling/src/derive_from_request.rs @@ -0,0 +1,46 @@ +use axum::{extract::rejection::JsonRejection, http::StatusCode, response::IntoResponse}; +use axum_macros::FromRequest; +use chrono::Utc; +use serde_json::{json, Value}; + +pub async fn handler(Json(value): Json) -> impl IntoResponse { + Json(dbg!(value)); +} + +// create an extractor that internally uses `axum::Json` but has a custom rejection +#[derive(FromRequest)] +#[from_request(via(axum::Json), rejection(ApiError))] +pub struct Json(T); + +#[derive(Debug)] +pub struct ApiError { + code: StatusCode, + message: String, +} + +impl From for ApiError { + fn from(rejection: JsonRejection) -> Self { + let code = match rejection { + JsonRejection::JsonDataError(_) | JsonRejection::MissingJsonContentType(_) => { + StatusCode::BAD_REQUEST + } + _ => StatusCode::INTERNAL_SERVER_ERROR, + }; + Self { + code, + message: rejection.to_string(), + } + } +} + +impl IntoResponse for ApiError { + fn into_response(self) -> axum::response::Response { + let payload = json!({ + "message": self.message, + "timestamp": Utc::now(), + "origin": "derive_from_request" + }); + + (self.code, axum::Json(payload)).into_response() + } +} diff --git a/examples/error-handling/src/main.rs b/examples/error-handling/src/main.rs index eb794f42..b4074dcc 100644 --- a/examples/error-handling/src/main.rs +++ b/examples/error-handling/src/main.rs @@ -1,5 +1,6 @@ -mod with_rejection; mod custom_extractor; +mod derive_from_request; +mod with_rejection; use axum::{routing::get, Router, Server}; use std::net::SocketAddr; @@ -17,7 +18,8 @@ async fn main() { // Build our application with some routes let app = Router::new() .route("/withRejection", get(with_rejection::handler)) - .route("/customExtractor", get(custom_extractor::handler)); + .route("/customExtractor", get(custom_extractor::handler)) + .route("/deriveFromRequest", get(derive_from_request::handler)); // Run our application let addr = SocketAddr::from(([127, 0, 0, 1], 3000));