From 0c8823ff269fe86c52e63ae443d8fe76dd67869f Mon Sep 17 00:00:00 2001 From: jprochazk Date: Sat, 21 Dec 2024 14:48:52 +0100 Subject: [PATCH] delete `axum_garde` --- Cargo.toml | 3 +- integrations/axum_garde/.gitignore | 4 - integrations/axum_garde/Cargo.toml | 57 ------- integrations/axum_garde/README.md | 43 ------ .../axum_garde/examples/custom_validation.rs | 65 -------- integrations/axum_garde/examples/json.rs | 58 ------- integrations/axum_garde/src/error.rs | 30 ---- integrations/axum_garde/src/into_inner.rs | 72 --------- integrations/axum_garde/src/lib.rs | 45 ------ .../axum_garde/src/with_validation.rs | 143 ------------------ integrations/axum_garde/tests/e2e.rs | 87 ----------- integrations/axum_garde/tests/impl_handler.rs | 90 ----------- .../axum_garde/tests/multiple_contexts.rs | 79 ---------- xtask/src/task/publish.rs | 1 - xtask/src/task/test.rs | 18 +-- 15 files changed, 4 insertions(+), 791 deletions(-) delete mode 100644 integrations/axum_garde/.gitignore delete mode 100644 integrations/axum_garde/Cargo.toml delete mode 100644 integrations/axum_garde/README.md delete mode 100644 integrations/axum_garde/examples/custom_validation.rs delete mode 100644 integrations/axum_garde/examples/json.rs delete mode 100644 integrations/axum_garde/src/error.rs delete mode 100644 integrations/axum_garde/src/into_inner.rs delete mode 100644 integrations/axum_garde/src/lib.rs delete mode 100644 integrations/axum_garde/src/with_validation.rs delete mode 100644 integrations/axum_garde/tests/e2e.rs delete mode 100644 integrations/axum_garde/tests/impl_handler.rs delete mode 100644 integrations/axum_garde/tests/multiple_contexts.rs diff --git a/Cargo.toml b/Cargo.toml index c3e57f0..8d8d89f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["garde_derive", "garde", "integrations/axum_garde"] +members = ["garde_derive", "garde"] resolver = "2" [workspace.package] @@ -9,7 +9,6 @@ version = "0.21.0" [workspace.dependencies] garde = { path = "garde", version = "=0.21.0", default-features = false } garde_derive = { path = "garde_derive", version = "=0.21.0", default-features = false } -axum_garde = { path = "integrations/axum_garde", version = "=0.21.0", default-features = false } [profile.dev.package] insta = { opt-level = 3 } diff --git a/integrations/axum_garde/.gitignore b/integrations/axum_garde/.gitignore deleted file mode 100644 index 975b01a..0000000 --- a/integrations/axum_garde/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/target -/Cargo.lock -.vscode -.idea diff --git a/integrations/axum_garde/Cargo.toml b/integrations/axum_garde/Cargo.toml deleted file mode 100644 index 5c22d73..0000000 --- a/integrations/axum_garde/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -name = "axum_garde" -version.workspace = true -rust-version.workspace = true -edition = "2021" -repository = "https://github.com/jprochazk/garde" -license = "MIT OR Apache-2.0" -description = "Deprecated in favor of axum-valid" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[badges] -maintenance.status = "deprecated" - -[package.metadata.docs.rs] -all-features = true - -[features] -default = ["json", "query", "form"] -# Axum -json = ["axum/json"] -query = ["axum/query"] -form = ["axum/form"] -# Axum extra -axum-extra-protobuf = ["axum-extra/protobuf"] -axum-extra-query = ["axum-extra/query"] - -[dependencies] -# Workspace -garde.workspace = true - -axum = { version = "0.7", default-features = false } -axum-extra = { version = "0.9", default-features = false, optional = true } -axum-yaml = { version = "0.4", default-features = false, optional = true } -axum-msgpack = { version = "0.4", default-features = false, optional = true } -thiserror = { version = "2.0.8", default-features = false } - -[dev-dependencies] -# Workspace -garde = { workspace = true, features = ["full", "derive"] } - -serde = { version = "1", features = ["derive"] } -serde_json = { version = "1" } -axum = { version = "0.7", features = ["default", "macros"] } -axum-test = { version = "16.4.1" } -tokio = { version = "1.28", features = ["full"] } -prost = { version = "0.12" } -rstest = { version = "0.23.0" } -speculoos = { version = "0.11" } - - -[[example]] -name = "json" -required-features = ["json"] - -[[example]] -name = "custom_validation" -required-features = ["json"] diff --git a/integrations/axum_garde/README.md b/integrations/axum_garde/README.md deleted file mode 100644 index 26f279e..0000000 --- a/integrations/axum_garde/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# axum_garde - -> [!WARNING] -> ⚠️ **This crate is deprecated in favor of [axum-valid](https://crates.io/crates/axum-valid).** ⚠️ - -Provide [garde](https://github.com/jprochazk/garde) validation on your -[axum](https://github.com/tokio-rs/axum) application. - -# Getting started - -The most important element on this library is [`WithValidation`], a composable -[`extractor`] that performs validation over some payload contents. - -For most validators to work, the application state should implement [`FromRef`] for `()`: -```rust -#[derive(Clone)] -struct AppState; - -impl axum::extract::FromRef for () { - fn from_ref(_: &AppState) {} -} -``` - -# Features - -| Feature | Description | Default? | -| --------------------- | ---------------------------------------------------------------------------------------------- | -------- | -| `json` | Enables support for [`axum::extract::Json`] | ✅ | -| `form` | Enables support for [`axum::extract::Form`] | ✅ | -| `query` | Enables support for [`axum::extract::Query`] | ✅ | -| `axum-extra` | Enables support for [`axum_extra::extract::WithRejection`] and [`axum_extra::extract::Cached`] | ❌ | -| `axum-extra-protobuf` | Enables support for [`axum_extra::protobuf::Protobuf`] | ❌ | -| `axum-extra-query` | Enables support for [`axum_extra::extract::Query`] | ❌ | -| `axum-yaml` | Enables support for [`axum_yaml::Yaml`] | ❌ | -| `axum-msgpack` | Enables support for [`axum_msgpack::MsgPack`] and [`axum_msgpack::MsgPackRaw`] | ❌ | - -# Useful links - - - -[`withvalidation`]: crate::WithValidation -[`extractor`]: axum::extract -[`FromRef`]: axum::extract::FromRef diff --git a/integrations/axum_garde/examples/custom_validation.rs b/integrations/axum_garde/examples/custom_validation.rs deleted file mode 100644 index 8122c7a..0000000 --- a/integrations/axum_garde/examples/custom_validation.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! Showcases custom validators and garde contexts -//! -//! Run the example using -//! -//! ```sh -//! cargo run --example custom_validation --features=json -//! ``` -use axum::response::IntoResponse; -use axum::routing::post; -use axum::{Json, Router}; -use axum_garde::WithValidation; -use garde::Validate; -use serde::{Deserialize, Serialize}; -use tokio::net::TcpListener; - -// Define your valid scheme -#[derive(Debug, Serialize, Deserialize, Validate)] -#[garde(context(PasswordContext))] -struct Person { - #[garde(ascii, length(min = 3, max = 25))] - username: String, - #[garde(custom(password_validation))] - password: String, -} - -// Define your custom context -#[derive(Debug, Clone)] -struct PasswordContext { - complexity: usize, -} - -// Define your custom validation -fn password_validation(value: &str, context: &PasswordContext) -> garde::Result { - if value.len() < context.complexity { - return Err(garde::Error::new("password is not strong enough")); - } - Ok(()) -} - -async fn insert_valid_person( - // Perform validation on the request payload - WithValidation(person): WithValidation>, -) -> impl IntoResponse { - println!("Inserted person on database: {person:?}"); - Json(person.into_inner()) -} - -#[tokio::main] -async fn main() { - let app = Router::new() - .route("/person", post(insert_valid_person)) - // Create the application state - .with_state(PasswordContext { complexity: 10 }); - - println!("See example: http://127.0.0.1:8080/person"); - - axum::serve( - TcpListener::bind("127.0.0.1:8080") - .await - .expect("Failed to bind the address"), - app.into_make_service(), - ) - .await - .expect("Failed to start axum serve"); -} diff --git a/integrations/axum_garde/examples/json.rs b/integrations/axum_garde/examples/json.rs deleted file mode 100644 index 6e6d75a..0000000 --- a/integrations/axum_garde/examples/json.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Simple usage of using `axum_garde` for a REST API -//! -//! Run the example using -//! -//! ```sh -//! cargo run --example json --features=json -//! ``` -use axum::response::IntoResponse; -use axum::routing::post; -use axum::{Json, Router}; -use axum_garde::WithValidation; -use garde::Validate; -use serde::{Deserialize, Serialize}; -use tokio::net::TcpListener; - -// Define your valid scheme -#[derive(Debug, Serialize, Deserialize, Validate)] -struct Person { - #[garde(ascii, length(min = 3, max = 25))] - username: String, - #[garde(length(min = 15))] - password: String, -} - -async fn insert_valid_person( - // Perform validation on the request payload - WithValidation(person): WithValidation>, -) -> impl IntoResponse { - println!("Inserted person on database: {person:?}"); - Json(person.into_inner()) -} - -#[derive(Clone)] -struct AppState; - -// This implementation is needed for most validators to work -impl axum::extract::FromRef for () { - fn from_ref(_: &AppState) {} -} - -#[tokio::main] -async fn main() { - let app = Router::new() - .route("/person", post(insert_valid_person)) - // Create the application state - .with_state(AppState); - - println!("See example: http://127.0.0.1:8080/person"); - - axum::serve( - TcpListener::bind("127.0.0.1:8080") - .await - .expect("Failed to bind the address"), - app.into_make_service(), - ) - .await - .expect("Failed to start axum serve"); -} diff --git a/integrations/axum_garde/src/error.rs b/integrations/axum_garde/src/error.rs deleted file mode 100644 index 68bb2b3..0000000 --- a/integrations/axum_garde/src/error.rs +++ /dev/null @@ -1,30 +0,0 @@ -use axum::http::StatusCode; -use axum::response::{IntoResponse, Response}; -use garde::Report; -use thiserror::Error; - -/// Rejection used for [`WithValidation`] -/// -/// [`WithValidation`]: crate::WithValidation -#[derive(Debug, Error)] -pub enum WithValidationRejection { - /// Variant for the extractor's rejection - #[error(transparent)] - ExtractionError(T), - - /// Variant for the payload's validation errors. Responds with status code - /// `422 Unprocessable Content` - #[error(transparent)] - ValidationError(#[from] Report), -} - -impl IntoResponse for WithValidationRejection { - fn into_response(self) -> Response { - match self { - WithValidationRejection::ExtractionError(t) => t.into_response(), - WithValidationRejection::ValidationError(e) => { - (StatusCode::UNPROCESSABLE_ENTITY, format!("{e}")).into_response() - } - } - } -} diff --git a/integrations/axum_garde/src/into_inner.rs b/integrations/axum_garde/src/into_inner.rs deleted file mode 100644 index cdc59f1..0000000 --- a/integrations/axum_garde/src/into_inner.rs +++ /dev/null @@ -1,72 +0,0 @@ -/// Trait for unwrapping extractor's payloads -/// -/// Types that extract data from request should implement this trait, as it -/// unlocks extractor composition with this library -pub trait IntoInner { - /// Wrapped payload type - type Inner; - /// Consume the extractor and unwrap the payload - fn into_inner(self) -> Self::Inner; -} - -macro_rules! impl_into_inner_simple { - ( - $name:ty, - [$($type_var:ident),* $(,)?] - ) => { - impl<$($type_var),*> IntoInner for $name { - type Inner = T; - fn into_inner(self) -> Self::Inner { - self.0 - } - } - }; -} - -#[cfg(feature = "axum-extra")] -macro_rules! impl_into_inner_wrapper { - ( - $name:ty, - $inner_type_var:ident, - [$($type_var:ident),* $(,)?] - ) => { - impl<$inner_type_var, $($type_var),*> IntoInner for $name - where - $inner_type_var: IntoInner, - { - type Inner = <$inner_type_var as IntoInner>::Inner; - fn into_inner(self) -> Self::Inner { - self.0.into_inner() - } - } - }; -} - -// Axum -#[cfg(feature = "json")] -impl_into_inner_simple!(axum::extract::Json, [T]); -impl_into_inner_simple!(axum::extract::Extension, [T]); -#[cfg(feature = "form")] -impl_into_inner_simple!(axum::extract::Form, [T]); -impl_into_inner_simple!(axum::extract::Path, [T]); -#[cfg(feature = "query")] -impl_into_inner_simple!(axum::extract::Query, [T]); -impl_into_inner_simple!(axum::extract::State, [T]); - -// Axum extra -#[cfg(feature = "axum-extra")] -impl_into_inner_wrapper!(axum_extra::extract::WithRejection, E, [T]); -#[cfg(feature = "axum-extra")] -impl_into_inner_wrapper!(axum_extra::extract::Cached, T, []); -#[cfg(feature = "axum-extra-protobuf")] -impl_into_inner_simple!(axum_extra::protobuf::Protobuf, [T]); -#[cfg(feature = "axum-extra-query")] -impl_into_inner_simple!(axum_extra::extract::Query, [T]); - -// Other -#[cfg(feature = "axum-yaml")] -impl_into_inner_simple!(axum_yaml::Yaml, [T]); -#[cfg(feature = "axum-msgpack")] -impl_into_inner_simple!(axum_msgpack::MsgPack, [T]); -#[cfg(feature = "axum-msgpack")] -impl_into_inner_simple!(axum_msgpack::MsgPackRaw, [T]); diff --git a/integrations/axum_garde/src/lib.rs b/integrations/axum_garde/src/lib.rs deleted file mode 100644 index 33c11bd..0000000 --- a/integrations/axum_garde/src/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![doc = include_str!("../README.md")] -#![warn( - clippy::all, - clippy::dbg_macro, - clippy::todo, - clippy::empty_enum, - clippy::enum_glob_use, - clippy::mem_forget, - clippy::unused_self, - clippy::filter_map_next, - clippy::needless_continue, - clippy::needless_borrow, - clippy::match_wildcard_for_single_variants, - clippy::if_let_mutex, - clippy::await_holding_lock, - clippy::match_on_vec_items, - clippy::imprecise_flops, - clippy::suboptimal_flops, - clippy::lossy_float_literal, - clippy::rest_pat_in_fully_bound_structs, - clippy::fn_params_excessive_bools, - clippy::exit, - clippy::inefficient_to_string, - clippy::linkedlist, - clippy::macro_use_imports, - clippy::option_option, - clippy::verbose_file_reads, - clippy::unnested_or_patterns, - clippy::str_to_string, - rust_2018_idioms, - future_incompatible, - nonstandard_style, - missing_debug_implementations, - missing_docs -)] -#![deny(unreachable_pub)] -#![forbid(unsafe_code)] - -mod error; -mod into_inner; -mod with_validation; - -pub use error::WithValidationRejection; -pub use into_inner::IntoInner; -pub use with_validation::WithValidation; diff --git a/integrations/axum_garde/src/with_validation.rs b/integrations/axum_garde/src/with_validation.rs deleted file mode 100644 index 1ae38ce..0000000 --- a/integrations/axum_garde/src/with_validation.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::fmt::Debug; -use std::ops::Deref; - -use axum::async_trait; -use axum::body::Body; -use axum::extract::{FromRef, FromRequest, FromRequestParts}; -use axum::http::request::Parts; -use axum::http::Request; -use garde::{Unvalidated, Valid, Validate}; - -use super::{IntoInner, WithValidationRejection}; - -/// An extractor for validating payloads with garde -/// -/// `WithValidation` wraps another extractor and validates it's payload. The -/// `T` generic type must be an [`extractor`] that implements `IntoInner`, -/// where `T::Inner: garde::Validate`. The validation context will be extracted -/// from the router's state. -/// -/// T is expected to implement [`FromRequest`] or [`FromRequestParts`], and -/// [`IntoInner`] -/// -/// The desired validation context ([`garde::Validate::Context`](garde::Validate)) -/// must be provided as router state -/// -/// ### Example -#[cfg_attr(feature = "json", doc = "```rust")] -#[cfg_attr(not(feature = "json"), doc = "```compile_fail")] -/// use axum::Json; -/// use serde::{Serialize,Deserialize}; -/// use garde::Validate; -/// use axum_garde::WithValidation; -/// -/// #[derive(Debug, Serialize, Deserialize, Validate)] -/// struct Person { -/// #[garde(length(min = 1, max = 10))] -/// name: String -/// } -/// -/// async fn handler( -/// WithValidation(valid_person): WithValidation>, -/// ) -> String{ -/// format!("{valid_person:?}") -/// } -/// -/// # // Assert that handler compiles -/// # axum::Router::new() -/// # .route("/", axum::routing::post(handler)) -/// # .with_state(()) -/// # .into_make_service(); -/// ``` -/// [`FromRequestParts`]: axum::extract::FromRequestParts -/// [`FromRequest`]: axum::extract::FromRequest -/// [`IntoInner`]: crate::IntoInner -/// [`Valid`]: garde::Valid -/// [`extractor`]: axum::extract -pub struct WithValidation(pub Valid) -where - Extractor: IntoInner; - -#[async_trait] -impl FromRequestParts for WithValidation -where - State: Send + Sync, - Extractor: FromRequestParts + IntoInner, - Extractor::Inner: Validate, - Context: FromRef, -{ - type Rejection = WithValidationRejection; - - async fn from_request_parts(parts: &mut Parts, state: &State) -> Result { - let value = Extractor::from_request_parts(parts, state) - .await - .map_err(WithValidationRejection::ExtractionError)?; - - let ctx = FromRef::from_ref(state); - let value = value.into_inner(); - let value = Unvalidated::new(value).validate_with(&ctx)?; - - Ok(WithValidation(value)) - } -} - -#[async_trait] -impl FromRequest for WithValidation -where - State: Send + Sync, - Extractor: FromRequest + IntoInner, - Extractor::Inner: Validate, - Context: FromRef, -{ - type Rejection = WithValidationRejection; - - async fn from_request(req: Request, state: &State) -> Result { - let value = Extractor::from_request(req, state) - .await - .map_err(WithValidationRejection::ExtractionError)?; - - let ctx = FromRef::from_ref(state); - let value = value.into_inner(); - let value = Unvalidated::new(value).validate_with(&ctx)?; - - Ok(WithValidation(value)) - } -} - -impl Debug for WithValidation -where - Extractor: IntoInner + Debug, - Extractor::Inner: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("WithValidation").field(&self.0).finish() - } -} - -impl Clone for WithValidation -where - Extractor: IntoInner + Clone, - Extractor::Inner: Clone, -{ - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl Copy for WithValidation -where - Extractor: IntoInner + Copy, - Extractor::Inner: Copy, -{ -} - -impl Deref for WithValidation -where - Extractor: IntoInner, -{ - type Target = Valid; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/integrations/axum_garde/tests/e2e.rs b/integrations/axum_garde/tests/e2e.rs deleted file mode 100644 index 0eaf122..0000000 --- a/integrations/axum_garde/tests/e2e.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![cfg(feature = "json")] - -use axum::http::StatusCode; -use axum::response::IntoResponse; -use axum::routing::{post, IntoMakeService}; -use axum::{debug_handler, Json, Router}; -use axum_garde::WithValidation; -use axum_test::TestServer; -use garde::Validate; -use rstest::*; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; -use speculoos::assert_that; - -#[derive(Debug, Serialize, Deserialize, Validate, PartialEq, Eq)] -struct Person { - #[garde(length(min = 1, max = 10))] - name: String, -} - -#[debug_handler] -async fn valid_echo_person_handler( - WithValidation(valid_person): WithValidation>, -) -> impl IntoResponse { - Json(valid_person.into_inner()) -} - -#[debug_handler] -async fn echo_person_handler(json: Json) -> impl IntoResponse { - json -} - -type AppState = (); - -#[fixture] -fn app_state() -> AppState { - Default::default() -} - -#[fixture] -fn router(app_state: AppState) -> IntoMakeService { - Router::new() - .route("/echo_person", post(echo_person_handler)) - .route("/valid_echo_person", post(valid_echo_person_handler)) - .with_state(app_state) - .into_make_service() -} - -#[fixture] -fn test_server(router: IntoMakeService) -> TestServer { - TestServer::new(router).unwrap() -} - -#[rstest] -#[case::hello(Person { name: "hello".into() })] -#[case::world(Person { name: "World".into() })] -#[tokio::test] -async fn assert_that_valid_requests_are_transparent( - test_server: TestServer, - #[case] payload: Person, -) { - let expected = test_server.post("/echo_person").json(&payload).await; - let obtained = test_server.post("valid_echo_person").json(&payload).await; - - assert_that!(obtained.headers()).is_equal_to(expected.headers()); - - obtained.assert_status(expected.status_code()); - obtained.assert_json(&expected.json::()); -} - -#[rstest] -#[case::not_a_person(StatusCode::UNPROCESSABLE_ENTITY, json!({"not": "a person"}))] -#[case::long_name(StatusCode::UNPROCESSABLE_ENTITY, json!({"name": "too long to be valid......."}))] -#[case::short_name(StatusCode::UNPROCESSABLE_ENTITY, json!({"name": ""}))] -#[tokio::test] -async fn assert_that_invalid_requests_are_sucessfully_rejected( - test_server: TestServer, - #[case] status_code: StatusCode, - #[case] payload: Value, -) { - let response = test_server - .post("/valid_echo_person") - .json(&payload) - .expect_failure() - .await; - response.assert_status(status_code); -} diff --git a/integrations/axum_garde/tests/impl_handler.rs b/integrations/axum_garde/tests/impl_handler.rs deleted file mode 100644 index 3572c51..0000000 --- a/integrations/axum_garde/tests/impl_handler.rs +++ /dev/null @@ -1,90 +0,0 @@ -use axum::response::IntoResponse; -use axum::routing::post; -use axum::Router; -use axum_garde::WithValidation; -use axum_test::TestServer; -use garde::Validate; -use prost::Message; -use rstest::*; -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -#[derive(Serialize, Deserialize, Validate, Message, Clone)] -struct Person { - #[prost(string, tag = "1")] - #[garde(length(min = 1))] - name: String, -} - -#[derive(Serialize, Deserialize, Debug, Validate)] -struct PathTuple(#[garde(length(min = 1))] pub String); - -#[derive(Debug, Error)] -enum CustomRejection { - #[cfg_attr(feature = "json", error(transparent))] - #[cfg(feature = "json")] - JsonRejection(#[from] axum::extract::rejection::JsonRejection), -} - -impl IntoResponse for CustomRejection { - fn into_response(self) -> axum::response::Response { - todo!("Mock implementation") - } -} - -macro_rules! gen_assert_impl { - ($test_name:ident,$extractor:ty) => { - #[rstest] - #[tokio::test] - async fn $test_name() { - #[axum::debug_handler] - async fn handler(_: WithValidation<$extractor>) {} - - let svc = Router::new().route("/", post(handler)).into_make_service(); - _ = TestServer::new(svc).unwrap(); - } - }; -} - -// Axum -#[cfg(feature = "json")] -gen_assert_impl!(assert_json_impl_handler, axum::extract::Json); -gen_assert_impl!( - assert_extension_impl_handler, - axum::extract::Extension -); -#[cfg(feature = "form")] -gen_assert_impl!(assert_form_impl_handler, axum::extract::Form); -gen_assert_impl!(assert_path_impl_handler, axum::extract::Path); -#[cfg(feature = "query")] -gen_assert_impl!(assert_query_impl_handler, axum::extract::Query); -gen_assert_impl!(assert_state_impl_handler, axum::extract::State<()>); - -// Axum extra -#[cfg(feature = "axum-extra-query")] -gen_assert_impl!( - assert_extra_query_impl_handler, - axum_extra::extract::Query -); -#[cfg(all(feature = "axum-extra", feature = "json"))] -gen_assert_impl!( - assert_withrejection_impl_handler, - axum_extra::extract::WithRejection, CustomRejection> -); - -#[cfg(feature = "axum-extra-protobuf")] -gen_assert_impl!( - assert_protobuf_impl_handler, - axum_extra::protobuf::Protobuf -); - -// Other -#[cfg(feature = "axum-msgpack")] -gen_assert_impl!(assert_mgspack_impl_handler, axum_msgpack::MsgPack); -#[cfg(feature = "axum-msgpack")] -gen_assert_impl!( - assert_mgspackraw_impl_handler, - axum_msgpack::MsgPackRaw -); -#[cfg(feature = "axum-yaml")] -gen_assert_impl!(assert_yaml_impl_handler, axum_yaml::Yaml); diff --git a/integrations/axum_garde/tests/multiple_contexts.rs b/integrations/axum_garde/tests/multiple_contexts.rs deleted file mode 100644 index db1a361..0000000 --- a/integrations/axum_garde/tests/multiple_contexts.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![cfg(feature = "json")] - -use axum::extract::FromRef; -use axum::http::StatusCode; -use axum::routing::{post, IntoMakeService}; -use axum::{Json, Router}; -use axum_garde::WithValidation; -use axum_test::TestServer; -use garde::Validate; -use rstest::*; -use serde::{Deserialize, Serialize}; -use serde_json::json; - -macro_rules! gen_custom_test { - ($name:ident, $context_name:ident, $custom_name:ident, $handler_name:ident) => { - #[derive(Debug, Validate, Serialize, Deserialize)] - #[garde(context($context_name))] - struct $name { - #[garde(custom($custom_name))] - name: String, - } - - #[derive(Debug, Clone, Copy, Default)] - struct $context_name; - - fn $custom_name(_: &str, _: &$context_name) -> garde::Result { - Ok(()) - } - - async fn $handler_name(_: WithValidation>) {} - }; -} - -gen_custom_test!(Cat, CatContext, custom_cat, cat_handler); -gen_custom_test!(Dog, DogContext, custom_dog, dog_handler); - -#[derive(Debug, Clone, Copy, Default, FromRef)] -struct AppState { - cat_context: CatContext, - dog_context: DogContext, -} - -#[fixture] -fn app_state() -> AppState { - Default::default() -} - -#[fixture] -fn router(app_state: AppState) -> IntoMakeService { - Router::new() - .route("/cat", post(cat_handler)) - .route("/dog", post(dog_handler)) - .with_state(app_state) - .into_make_service() -} -#[fixture] -fn test_server(router: IntoMakeService) -> TestServer { - TestServer::new(router).unwrap() -} - -#[rstest] -#[case::cat("/cat", json!({"name": "kitty"}))] -#[case::dog("/dog", json!({"name": "doggy"}))] -#[trace] -#[tokio::test] -async fn assert_that_state_can_contain_multiple_contexts( - #[case] path: &'static str, - #[case] payload: serde_json::Value, - test_server: TestServer, -) { - // Perform the request - // Although the type system has verified that multiple contexts can coexist, - // we perform the request to verify no runtime errors (eg panics) happens - test_server - .post(path) - .json(&payload) - .await - .assert_status(StatusCode::OK); -} diff --git a/xtask/src/task/publish.rs b/xtask/src/task/publish.rs index ad89a3f..db14a11 100644 --- a/xtask/src/task/publish.rs +++ b/xtask/src/task/publish.rs @@ -11,7 +11,6 @@ impl Publish { pub fn run(self) -> Result { cargo("publish").with_args(["-p", "garde_derive"]).run()?; cargo("publish").with_args(["-p", "garde"]).run()?; - cargo("publish").with_args(["-p", "axum_garde"]).run()?; Ok(()) } diff --git a/xtask/src/task/test.rs b/xtask/src/task/test.rs index 2914651..246b305 100644 --- a/xtask/src/task/test.rs +++ b/xtask/src/task/test.rs @@ -27,17 +27,13 @@ enum Target { Doc, Ui, Rules, - Axum, } struct InvalidTarget; impl std::fmt::Display for InvalidTarget { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "invalid target, expected one of: unit, doc, ui, rules, axum" - ) + write!(f, "invalid target, expected one of: unit, doc, ui, rules") } } @@ -48,22 +44,19 @@ impl argp::FromArgValue for Target { ("doc", Self::Doc), ("ui", Self::Ui), ("rules", Self::Rules), - ("axum", Self::Axum), ] .into_iter() .find(|(name, _)| value.eq_ignore_ascii_case(std::ffi::OsStr::new(name))) .map(|(_, target)| target) - .ok_or_else(|| "invalid target, expected one of: unit, doc, ui, rules, axum".into()) + .ok_or_else(|| "invalid target, expected one of: unit, doc, ui, rules".into()) } } impl Test { pub fn run(mut self) -> Result { let review = self.review; - let mut commands = if self.targets.is_empty() && self.wasm { + let mut commands = if self.targets.is_empty() { vec![unit(), ui(review), rules(review)] - } else if self.targets.is_empty() { - vec![unit(), ui(review), rules(review), axum()] } else { self.targets.sort(); BTreeSet::from_iter(self.targets) @@ -73,7 +66,6 @@ impl Test { Target::Doc => doc(), Target::Ui => ui(review), Target::Rules => rules(review), - Target::Axum => axum(), }) .collect() }; @@ -132,7 +124,3 @@ fn rules(review: bool) -> Command { cargo("test").with_args(["--package=garde", "--all-features", "--test=rules"]) } } - -fn axum() -> Command { - cargo("test").with_args(["--package=axum_garde", "--all-features"]) -}