51 releases (24 breaking)
0.25.0 | Sep 7, 2024 |
---|---|
0.24.0 | Jun 22, 2024 |
0.23.0 | Jun 20, 2024 |
0.19.0 | Mar 2, 2024 |
0.6.2 | Jul 31, 2022 |
#80 in Encoding
62,757 downloads per month
Used in 18 crates
(12 directly)
225KB
4.5K
SLoC
Serde Valid
This is JSON Schema based validation tool using serde.
Usage
You derive Validate
trait, and write validations.
use serde_valid::Validate;
#[derive(Validate)]
struct Data {
#[validate(minimum = 0)]
#[validate(maximum = 10)]
val: i32,
}
#[derive(Validate)]
enum DataEnum {
Named {
#[validate]
a: Data,
},
}
let s = DataEnum::Named {
a: Data { val: 5 },
};
assert!(s.validate().is_ok());
Feature Flags
toml
- provide serialization/deserialization intoml
format.yaml
- provide serialization/deserialization inyaml
format.i128
- supporti128
/u128
type (default).fluent
- provide localization using fluent.
Validations
Serde Valid support standard validation based JSON Schema.
Type | Serde Valid (validate derive) | Serde Valid (validate trait) | JSON Schema |
---|---|---|---|
String | #[validate(max_length = 5)] |
ValidateMaxLength |
maxLength |
String | #[validate(min_length = 5)] |
ValidateMinLength |
minLength |
String | #[validate(pattern = r"^\d{5}$")] |
ValidatePattern |
pattern |
Numeric | #[validate(maximum = 5)] |
ValidateMaximum |
maximum |
Numeric | #[validate(minimum = 5)] |
ValidateMinimum |
minimum |
Numeric | #[validate(exclusive_maximum = 5)] |
ValidateExclusiveMaximum |
exclusiveMaximum |
Numeric | #[validate(exclusive_minimum = 5)] |
ValidateExclusiveMinimum |
exclusiveMinimum |
Numeric | #[validate(multiple_of = 5)] |
ValidateMultipleOf |
multipleOf |
Object | #[validate(max_properties = 5)] |
ValidateMaxProperties |
maxProperties |
Object | #[validate(min_properties = 5)] |
ValidateMinProperties |
minProperties |
Array | #[validate(max_items = 5)] |
ValidateMaxItems |
maxItems |
Array | #[validate(min_items = 5)] |
ValidateMinItems |
minItems |
Array | #[validate(unique_items)] |
ValidateUniqueItems |
uniqueItems |
Generic | #[validate(enumerate = [5, 10, 15])] |
ValidateEnumerate |
enum |
In addition, [serde_valid::utils][module@crate::utils] provides a type of validation not described in the JSON schema specification.
Type | Serde Valid (validate derive) | Serde Valid (validation function) |
---|---|---|
Duration | #[validate(custom = duration_maximum(SECOND))] |
duration_maximum |
Duration | #[validate(custom = duration_minimum(ZERO))] |
duration_minimum |
Duration | #[validate(custom = duration_exclusive_maximum(SECOND))] |
duration_exclusive_maximum |
Duration | #[validate(custom = duration_exclusive_minimum(ZERO))] |
duration_exclusive_minimum |
Complete Constructor (Deserialization)
Serde Valid support complete constructor method using by
serde_valid::json::FromJsonValue
trait.
use serde::Deserialize;
use serde_valid::Validate;
use serde_valid::json::{json, FromJsonValue};
#[derive(Debug, Deserialize, Validate)]
struct Data {
#[validate(maximum = 100)]
val: i32,
}
// Deserialization and Validation!! ๐
let err = Data::from_json_value(json!({ "val": 123 })).unwrap_err();
assert_eq!(
err.to_string(),
json!({
"errors": [],
"properties": {
"val": {
"errors": ["The number must be `<= 100`."]
}
}
})
.to_string()
);
You can force validation by only deserialization through serde_valid
, and removing
serde_json
from Cargo.toml
of your project.
Serialization
For serialization, provides serde_valid::json::ToJsonString
trait.
use serde::Serialize;
use serde_valid::Validate;
use serde_valid::json::{json, ToJsonString};
#[derive(Debug, Serialize, Validate)]
struct Data {
#[validate(maximum = 100)]
val: i32,
}
assert_eq!(
Data{ val: 12i32 }.to_json_string().unwrap(),
json!({ "val": 12i32 }).to_json_string().unwrap()
);
Custom Message
For user custom message, Serde Valid provides message_fn
or message
.
use serde_json::json;
use serde_valid::Validate;
#[inline]
fn min_error_message(_params: &serde_valid::MinItemsError) -> String {
"this is custom message_fn.".to_string()
}
#[derive(Validate)]
struct Data {
#[validate(min_items = 4, message_fn = min_error_message)]
#[validate(max_items = 2, message = "this is custom message.")]
val: Vec<i32>,
}
let s = Data { val: vec![1, 2, 3] };
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"properties": {
"val": {
"errors": [
"this is custom message_fn.",
"this is custom message."
]
}
}
})
.to_string()
);
Fluent localization
fluent
feature is required.
You can also use fluent localization by using fluent
feature.
Allow the following attributes:
#[validate(..., fluent("message-id", key1 = value1, ...))]
#[validate(..., message_l10n = fluent("message-id", key1 = value1, ...))]
use unic_langid::LanguageIdentifier;
use serde_json::json;
use serde_valid::{fluent::Localize, Validate};
#[derive(Validate)]
struct Data (
#[validate(min_length = 3, fluent("name-min-length", min_length = 3))]
String,
);
assert_eq!(
Data("็ฐไธญ".to_string()).validate()
.unwrap_err()
.localize(&get_bundle("name-min-length = ๅๅใฎ้ทใใฏ { $min_length } ๆๅญไปฅไธใงใชใใจใใใพใใใ"))
.to_string(),
json!({
"errors": ["ๅๅใฎ้ทใใฏ \u{2068}3\u{2069} ๆๅญไปฅไธใงใชใใจใใใพใใใ"]
})
.to_string()
);
Custom Validation
Single Error Validation
You can use your custom validation using by #[validate(custom = ...)]
.
use serde_valid::Validate;
fn user_validation(_val: &i32) -> Result<(), serde_valid::validation::Error> {
Ok(())
}
#[derive(Validate)]
struct Data {
#[validate(custom = user_validation)]
val: i32,
}
let s = Data { val: 1 };
assert!(s.validate().is_ok());
And you can also use closure.
use serde_valid::Validate;
fn user_validation(_val: &i32, param1: bool) -> Result<(), serde_valid::validation::Error> {
Ok(())
}
#[derive(Validate)]
struct Data {
#[validate(custom = |v| user_validation(v, true))]
val: i32,
}
let s = Data { val: 1 };
assert!(s.validate().is_ok());
Custom validation is suitable for handling convenience validations not defined in JSON Schema.
serde_valid::utils::*
provides convenience functions for specific types.
use serde_json::json;
use serde_valid::Validate;
use serde_valid::utils::{duration_maximum, duration_minimum};
#[derive(Validate)]
struct Data {
#[validate(custom = duration_maximum(std::time::Duration::from_micros(5)))]
#[validate(custom = duration_minimum(std::time::Duration::from_micros(0)))]
val1: std::time::Duration,
}
let s = Data {
val1: std::time::Duration::from_micros(1),
};
assert!(s.validate().is_ok());
Multi Errors Validation
If you want to return multiple errors in the use custom validation method, you can use #[validate(custom = ...)]
same as single error.
use serde_valid::Validate;
// ๐ Just change the return type from `Result<(), Error>` to `Result<(), Vec<Error>>` !!
fn user_validation(_val: &i32) -> Result<(), Vec<serde_valid::validation::Error>> {
Ok(())
}
#[derive(Validate)]
struct Data {
#[validate(custom = user_validation)]
val: i32,
}
let s = Data { val: 1 };
assert!(s.validate().is_ok());
Multi Fields Validation
Now, you can use #[validate(custom = ...)]
for multi fields validation.
use serde_json::json;
use serde_valid::Validate;
fn sample_validation(val1: i32, val2: &str) -> Result<(), serde_valid::validation::Error> {
Ok(())
}
#[derive(Validate)]
#[validate(custom = |s| sample_validation(s.val1, &s.val2))]
struct Data {
val1: i32,
val2: String,
}
let s = Data {
val1: 1,
val2: "val2".to_owned(),
};
assert!(s.validate().is_ok());
Validate Traits
By implementing the validation trait, Your original type can uses Serde Valid validations.
use serde_valid::Validate;
struct MyType(String);
impl serde_valid::ValidateMaxLength for MyType {
fn validate_max_length(&self, max_length: usize) -> Result<(), serde_valid::MaxLengthError> {
self.0.validate_max_length(max_length)
}
}
#[derive(Validate)]
struct Data {
#[validate(max_length = 5)]
val: MyType,
}
let s = Data {
val: MyType(String::from("๐๐บ๐๐ฝ๐จโ๐ค๐จโ๐ฉโ๐งโ๐ฆ")),
};
assert!(s.validate().is_ok());
Validation Errors Format
Named Struct
Field errors are output to properties
.
use serde_json::json;
use serde_valid::Validate;
#[derive(Validate)]
struct Data {
#[validate(maximum = 4)]
val: u32,
}
let s = Data { val: 5 };
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"properties": {
"val": {
"errors": ["The number must be `<= 4`."]
}
}
})
.to_string()
);
Unnamed Struct
Field errors are output to items
. The key for items
is guaranteed to be a string of positive
numbers.
use serde_json::json;
use serde_valid::Validate;
#[derive(Validate)]
struct Data (
#[validate(maximum = 4)] u32,
#[validate(maximum = 3)] u32,
);
let s = Data ( 5, 4 );
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"items": {
"0": {
"errors": ["The number must be `<= 4`."]
},
"1": {
"errors": ["The number must be `<= 3`."]
}
}
})
.to_string()
);
New Type
Field errors are output to errors
.
use serde_json::json;
use serde_valid::Validate;
#[derive(Validate)]
struct Data (
#[validate(maximum = 4)] u32
);
let s = Data (5);
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": ["The number must be `<= 4`."]
})
.to_string()
);
Named Enum
Variant errors are output to properties
.
use serde_json::json;
use serde_valid::Validate;
#[derive(Validate)]
enum Data {
Named {
#[validate(maximum = 5)]
a: i32,
#[validate(maximum = 5)]
b: i32,
},
}
let s = Data::Named { a: 6, b: 6 };
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"properties": {
"a": {
"errors": ["The number must be `<= 5`."]
},
"b": {
"errors": ["The number must be `<= 5`."]
}
}
})
.to_string()
);
Unnamed Enum
Variant errors are output to items
. The key for items
is guaranteed to be a string of
positive numbers.
use serde_json::json;
use serde_valid::Validate;
#[derive(Validate)]
enum Data {
Unnamed (
#[validate(maximum = 5)] i32,
#[validate(maximum = 5)] i32,
),
}
let s = Data::Unnamed ( 6, 6 );
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": [],
"items": {
"0": {
"errors": ["The number must be `<= 5`."]
},
"1": {
"errors": ["The number must be `<= 5`."]
}
}
})
.to_string()
);
New Type Enum
Variant errors are output to errors
.
use serde_json::json;
use serde_valid::Validate;
#[derive(Validate)]
enum Data {
NewType (
#[validate(maximum = 5)] i32,
),
}
let s = Data::NewType ( 6 );
assert_eq!(
s.validate().unwrap_err().to_string(),
json!({
"errors": ["The number must be `<= 5`."]
})
.to_string()
);
Dependencies
~4.5โ7MB
~129K SLoC