From ccf6dc46b89d8e02c8e9577906ab58ff90e315bb Mon Sep 17 00:00:00 2001 From: Elad Kaplan Date: Thu, 11 Jan 2024 11:08:24 +0200 Subject: [PATCH 1/2] handle invald payload Json reqeust with rejection schema response --- Cargo.toml | 2 +- examples/demo/Cargo.lock | 13 +++++++++++++ src/controller/format.rs | 10 +++------- src/controller/health.rs | 4 ++-- src/controller/mod.rs | 15 ++++++++++++--- src/controller/ping.rs | 4 ++-- src/errors.rs | 14 ++++++++++---- src/prelude.rs | 3 +-- 8 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eede1a1f9..c91e7ba3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ rusty-sidekiq = { version = "0.8.2", default-features = false } async-trait = "0.1.74" bb8 = "0.8.1" -axum = "0.7.1" +axum = { version = "0.7.1", features = ["macros"] } axum-extra = { version = "0.9", features = ["cookie"] } regex = "1" lazy_static = "1.4.0" diff --git a/examples/demo/Cargo.lock b/examples/demo/Cargo.lock index 53a183a85..b769974a7 100644 --- a/examples/demo/Cargo.lock +++ b/examples/demo/Cargo.lock @@ -425,6 +425,7 @@ checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", "axum-core", + "axum-macros", "bytes", "futures-util", "http", @@ -492,6 +493,18 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a2edad600410b905404c594e2523549f1bcd4bded1e252c8f74524ccce0b867" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "axum-test" version = "14.0.0" diff --git a/src/controller/format.rs b/src/controller/format.rs index 781abc9bd..cd191a97b 100644 --- a/src/controller/format.rs +++ b/src/controller/format.rs @@ -8,8 +8,7 @@ //! Rust struct. //! //! ```rust -//! use loco_rs::{controller::format, Result}; -//! use axum::Json; +//! use loco_rs::{controller::{Json, format}, Result}; //! //! pub struct Health { //! pub ok: bool, @@ -20,19 +19,17 @@ //! } //! ``` +use crate::{controller::Json, Result}; use axum::{ body::Body, http::{response::Builder, HeaderName, HeaderValue}, response::{Html, Response}, - Json, }; use axum_extra::extract::cookie::Cookie; use bytes::{BufMut, BytesMut}; use hyper::{header, StatusCode}; use serde::Serialize; -use crate::Result; - /// Returns an empty response. /// /// # Example: @@ -84,10 +81,9 @@ pub fn text(t: &str) -> Result { /// /// ```rust /// use loco_rs::{ -/// controller::format, +/// controller::{Json, format}, /// Result, /// }; -/// use axum::Json; /// /// pub struct Health { /// pub ok: bool, diff --git a/src/controller/health.rs b/src/controller/health.rs index 30e5cd0a9..3e1acbb41 100644 --- a/src/controller/health.rs +++ b/src/controller/health.rs @@ -2,11 +2,11 @@ //! reporting. These routes are commonly used to monitor the health of the //! application and its dependencies. -use axum::{extract::State, routing::get, Json}; +use axum::{extract::State, routing::get}; use serde::Serialize; use super::{format, routes::Routes}; -use crate::{app::AppContext, redis, Result}; +use crate::{app::AppContext, controller::Json, redis, Result}; /// Represents the health status of the application. #[derive(Serialize)] diff --git a/src/controller/mod.rs b/src/controller/mod.rs index 100207c62..8a5c8890f 100644 --- a/src/controller/mod.rs +++ b/src/controller/mod.rs @@ -78,7 +78,6 @@ pub use app_routes::{AppRoutes, ListRoutes}; use axum::{ http::StatusCode, response::{IntoResponse, Response}, - Json, }; use colored::Colorize; pub use routes::Routes; @@ -98,10 +97,9 @@ use crate::{errors::Error, Result}; /// # Example /// /// ```rust -/// use axum::Json; /// use loco_rs::{ /// Result, -/// controller::{format, unauthorized} +/// controller::{format, Json, unauthorized} /// }; /// /// async fn login() -> Result> { @@ -153,6 +151,17 @@ impl ErrorDetail { } } +use axum::extract::FromRequest; +#[derive(Debug, FromRequest)] +#[from_request(via(axum::Json), rejection(Error))] +pub struct Json(pub T); + +impl IntoResponse for Json { + fn into_response(self) -> axum::response::Response { + axum::Json(self.0).into_response() + } +} + impl IntoResponse for Error { /// Convert an `Error` into an HTTP response. fn into_response(self) -> Response { diff --git a/src/controller/ping.rs b/src/controller/ping.rs index f93878107..a7ab4bba4 100644 --- a/src/controller/ping.rs +++ b/src/controller/ping.rs @@ -2,11 +2,11 @@ //! reporting. These routes are commonly used to monitor the health of the //! application and its dependencies. -use axum::{routing::get, Json}; +use axum::routing::get; use serde::Serialize; use super::{format, routes::Routes}; -use crate::Result; +use crate::{controller::Json, Result}; /// Represents the health status of the application. #[derive(Serialize)] diff --git a/src/errors.rs b/src/errors.rs index 7905f4202..9260f637c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,9 +1,12 @@ //! # Application Error Handling -use axum::http::{ - header::{InvalidHeaderName, InvalidHeaderValue}, - method::InvalidMethod, - StatusCode, +use axum::{ + extract::rejection::JsonRejection, + http::{ + header::{InvalidHeaderName, InvalidHeaderValue}, + method::InvalidMethod, + StatusCode, + }, }; use lettre::{address::AddressError, transport::smtp}; @@ -47,6 +50,9 @@ pub enum Error { #[error(transparent)] JSON(serde_json::Error), + #[error(transparent)] + JsonRejection(#[from] JsonRejection), + #[error("cannot parse `{1}`: {0}")] YAMLFile(#[source] serde_yaml::Error, String), diff --git a/src/prelude.rs b/src/prelude.rs index 46b86fc1a..2405db2fa 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,7 +2,6 @@ pub use async_trait::async_trait; pub use axum::{ extract::{Form, Path, State}, routing::{delete, get, post, put}, - Json, }; pub use axum_extra::extract::cookie; pub use chrono::NaiveDateTime as DateTime; @@ -14,7 +13,7 @@ pub use sea_orm::{ActiveModelTrait, EntityTrait, IntoActiveModel, ModelTrait, Se pub use crate::controller::middleware::auth; pub use crate::{ app::AppContext, - controller::{format, not_found, unauthorized, Routes}, + controller::{format, not_found, unauthorized, Json, Routes}, errors::Error, mailer, mailer::Mailer, From df3b8fa386703ca96d0d091d45066fd1c02b2796 Mon Sep 17 00:00:00 2001 From: Elad Kaplan Date: Thu, 11 Jan 2024 11:22:23 +0200 Subject: [PATCH 2/2] fix docs --- src/controller/middleware/auth.rs | 7 ++----- src/controller/routes.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/controller/middleware/auth.rs b/src/controller/middleware/auth.rs index dac6fd49d..ea0520200 100644 --- a/src/controller/middleware/auth.rs +++ b/src/controller/middleware/auth.rs @@ -4,14 +4,11 @@ //! //! ``` //! use loco_rs::{ -//! controller::{middleware, format}, +//! controller::{middleware, format, Json}, //! app::AppContext, //! Result, //! }; -//! use axum::{ -//! Json, -//! extract::State -//! }; +//! use axum::extract::State; //! //! pub struct TestResponse { //! pub pid: String, diff --git a/src/controller/routes.rs b/src/controller/routes.rs index 541a44e36..306f77b99 100644 --- a/src/controller/routes.rs +++ b/src/controller/routes.rs @@ -31,10 +31,10 @@ impl Routes { /// /// ```rust /// use loco_rs::{ - /// controller::{Routes, format}, + /// controller::{Routes, format, Json}, /// Result, /// }; - /// use axum::{routing::get, Json}; + /// use axum::routing::get; /// use serde::Serialize;; /// /// #[derive(Serialize)] @@ -65,9 +65,9 @@ impl Routes { /// ```rust /// use loco_rs::{ /// Result, - /// controller::{Routes, format}, + /// controller::{Routes, format, Json}, /// }; - /// use axum::{routing::get, Json}; + /// use axum::routing::get; /// use serde::Serialize; /// /// #[derive(Serialize)] @@ -101,10 +101,10 @@ impl Routes { /// /// ```rust /// use loco_rs::{ - /// controller::{Routes, format}, + /// controller::{Routes, format, Json}, /// Result, /// }; - /// use axum::{routing::get, Json}; + /// use axum::routing::get; /// use serde::Serialize; /// /// #[derive(Serialize)]