add feature 422 and update version to 0.4.0

This commit is contained in:
gengteng
2023-08-01 12:55:40 +08:00
parent 91ce221dd3
commit 8da4d2519d
7 changed files with 28 additions and 10 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/target /target
/Cargo.lock /Cargo.lock
/.idea /.idea
/lcov.info

View File

@@ -44,3 +44,4 @@ json = ["axum/json"]
form = ["axum/form"] form = ["axum/form"]
query = ["axum/query"] query = ["axum/query"]
into_json = ["serde_json"] into_json = ["serde_json"]
422 = []

View File

@@ -44,8 +44,11 @@ pub async fn get_page_by_json(
} }
``` ```
When validation errors occur, the extractor will automatically return 400 with validation errors as the HTTP message body.
For more usage examples, please refer to the `basic.rs` and `custom.rs` files in the `tests` directory. For more usage examples, please refer to the `basic.rs` and `custom.rs` files in the `tests` directory.
## Features ## Features
`422`: Use `422 Unprocessable Entity` instead of `400 Bad Request` as the status code when validation fails.
`into_json`: When this feature is enabled, validation errors will be serialized into JSON format and returned as the HTTP body. `into_json`: When this feature is enabled, validation errors will be serialized into JSON format and returned as the HTTP body.

View File

@@ -16,6 +16,13 @@ use axum::http::{Request, StatusCode};
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use validator::{Validate, ValidationErrors}; use validator::{Validate, ValidationErrors};
/// Http status code returned when there are validation errors.
#[cfg(feature = "422")]
pub const VALIDATION_ERROR_STATUS: StatusCode = StatusCode::UNPROCESSABLE_ENTITY;
/// Http status code returned when there are validation errors.
#[cfg(not(feature = "422"))]
pub const VALIDATION_ERROR_STATUS: StatusCode = StatusCode::BAD_REQUEST;
/// Valid entity extractor /// Valid entity extractor
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Valid<T>(pub T); pub struct Valid<T>(pub T);
@@ -41,14 +48,14 @@ impl<E: IntoResponse> IntoResponse for ValidRejection<E> {
ValidRejection::Valid(validate_error) => { ValidRejection::Valid(validate_error) => {
#[cfg(feature = "into_json")] #[cfg(feature = "into_json")]
match serde_json::to_string(&validate_error) { match serde_json::to_string(&validate_error) {
Ok(json) => (StatusCode::BAD_REQUEST, json), Ok(json) => (VALIDATION_ERROR_STATUS, json),
Err(error) => ( Err(error) => (
StatusCode::INTERNAL_SERVER_ERROR, StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to serialize validation error into JSON ({validate_error}): {error}"), format!("Failed to serialize validation error into JSON ({validate_error}): {error}"),
), ),
} }
#[cfg(not(feature = "into_json"))] #[cfg(not(feature = "into_json"))]
(StatusCode::BAD_REQUEST, validate_error.to_string()) (VALIDATION_ERROR_STATUS, validate_error.to_string())
}.into_response(), }.into_response(),
ValidRejection::Inner(json_error) => json_error.into_response(), ValidRejection::Inner(json_error) => json_error.into_response(),
} }

View File

@@ -1,4 +1,10 @@
[feature_default] [feature_default]
[feature_into_json] [feature_into_json]
features = "into_json" features = "into_json"
[feature_422]
features = "422"
[feature_422_into_json]
features = "422 into_json"

View File

@@ -9,7 +9,7 @@ use axum::extract::{Path, Query};
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::routing::{get, post}; use axum::routing::{get, post};
use axum::{Form, Json, Router}; use axum::{Form, Json, Router};
use axum_valid::Valid; use axum_valid::{Valid, VALIDATION_ERROR_STATUS};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use std::net::SocketAddr; use std::net::SocketAddr;
@@ -76,7 +76,7 @@ async fn main() -> anyhow::Result<()> {
)) ))
.send() .send()
.await?; .await?;
assert_eq!(invalid_path_response.status(), StatusCode::BAD_REQUEST); assert_eq!(invalid_path_response.status(), VALIDATION_ERROR_STATUS);
#[cfg(feature = "into_json")] #[cfg(feature = "into_json")]
assert!(invalid_path_response assert!(invalid_path_response
.json::<serde_json::Value>() .json::<serde_json::Value>()
@@ -105,7 +105,7 @@ async fn main() -> anyhow::Result<()> {
.query(&invalid_parameters) .query(&invalid_parameters)
.send() .send()
.await?; .await?;
assert_eq!(invalid_query_response.status(), StatusCode::BAD_REQUEST); assert_eq!(invalid_query_response.status(), VALIDATION_ERROR_STATUS);
#[cfg(feature = "into_json")] #[cfg(feature = "into_json")]
assert!(invalid_query_response assert!(invalid_query_response
.json::<serde_json::Value>() .json::<serde_json::Value>()
@@ -137,7 +137,7 @@ async fn main() -> anyhow::Result<()> {
.form(&invalid_parameters) .form(&invalid_parameters)
.send() .send()
.await?; .await?;
assert_eq!(invalid_form_response.status(), StatusCode::BAD_REQUEST); assert_eq!(invalid_form_response.status(), VALIDATION_ERROR_STATUS);
#[cfg(feature = "into_json")] #[cfg(feature = "into_json")]
assert!(invalid_form_response assert!(invalid_form_response
.json::<serde_json::Value>() .json::<serde_json::Value>()
@@ -169,7 +169,7 @@ async fn main() -> anyhow::Result<()> {
.json(&invalid_parameters) .json(&invalid_parameters)
.send() .send()
.await?; .await?;
assert_eq!(invalid_json_response.status(), StatusCode::BAD_REQUEST); assert_eq!(invalid_json_response.status(), VALIDATION_ERROR_STATUS);
#[cfg(feature = "into_json")] #[cfg(feature = "into_json")]
assert!(invalid_json_response assert!(invalid_json_response
.json::<serde_json::Value>() .json::<serde_json::Value>()

View File

@@ -6,7 +6,7 @@ use axum::http::request::Parts;
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use axum::routing::get; use axum::routing::get;
use axum::Router; use axum::Router;
use axum_valid::{HasValidate, Valid, ValidRejection}; use axum_valid::{HasValidate, Valid, ValidRejection, VALIDATION_ERROR_STATUS};
use hyper::StatusCode; use hyper::StatusCode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::SocketAddr; use std::net::SocketAddr;
@@ -122,7 +122,7 @@ async fn main() -> anyhow::Result<()> {
.header(MY_DATA_HEADER, serde_json::to_string(&invalid_my_data)?) .header(MY_DATA_HEADER, serde_json::to_string(&invalid_my_data)?)
.send() .send()
.await?; .await?;
assert_eq!(invalid_my_data_response.status(), StatusCode::BAD_REQUEST); assert_eq!(invalid_my_data_response.status(), VALIDATION_ERROR_STATUS);
#[cfg(feature = "into_json")] #[cfg(feature = "into_json")]
assert!(invalid_my_data_response assert!(invalid_my_data_response
.json::<serde_json::Value>() .json::<serde_json::Value>()