Dependence
To handle JSON, let’s first add serde
and serde_json
to your project.
cargo add serde --features derive
cargo add serde_json
Or add the following to your Cargo.toml
:
[dependencies]
serde = { version = "x.x.x", features = ["derive"] }
serde_json = "x.x.x"
Let’s get started
First, let’s envision a scenario where we validate incoming JSON data.
For example, let’s say we want data that meets the following requirements.
name
field that is not empty.
age
field that falls within the range of 18 to 80.
friends
field containing at least one entry, each with a name that is not empty.
We can define the rules for each field as follows:
use refined_type::rule::{MinMaxU8, NonEmptyString, NonEmptyVec};
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Data {
name: NonEmptyString,
age: MinMaxU8<18, 80>,
friends: NonEmptyVec<NonEmptyString>,
}
Valid JSON case
Now, let’s try to deserialize the valid JSON data.
fn main() {
let json = r#"{
"name": "john",
"age": 55,
"friends": ["tom", "hanako"]
}"#;
let my_struct = serde_json::from_str::<Data>(json);
println!("{:?}", my_struct);
}
Ok(Data { name: Refined { value: "john" }, age: Refined { value: 55 }, friends: Refined { value: [Refined { value: "tom" }, Refined { value: "hanako" }] } })
The JSON data meets the requirements, so it is successfully deserialized.
Invalid JSON case
Next, let’s try to deserialize JSON data that does not meet the requirements.
name
field is empty
fn main() {
let json = r#"{
"name": "",
"age": 55,
"friends": ["tom", "hamako"]
}"#;
let my_struct = serde_json::from_str::<Data>(json);
println!("{:?}", my_struct);
}
$ cargo run
Err(Error("\"\" does not satisfy Not<refined_type::rule::empty::EmptyRule<alloc::string::String>>", line: 2, column: 18))
age
field is out of range
fn main() {
let json = r#"{
"name": "john",
"age": 10,
"friends": ["tom", "hanako"]
}"#;
let my_struct = serde_json::from_str::<Data>(json);
println!("{:?}", my_struct);
}
$ cargo run
Err(Error("[the value must be equal to 18, but received 10 || the value must be greater than 18, but received 10]", line: 3, column: 17))
friends
field is empty
fn main() {
let json = r#"{
"name": "john",
"age": 55,
"friends": []
}"#;
let my_struct = serde_json::from_str::<Data>(json);
println!("{:?}", my_struct);
}
$ cargo run
Err(Error("[] does not satisfy Not<refined_type::rule::empty::EmptyRule<alloc::vec::Vec<refined_type::refined::Refined<Not<refined_type::rule::empty::EmptyRule<alloc::string::String>>>>>>", line: 5, column: 5))
friends
field is not empty, but the name is empty
fn main() {
let json = r#"{
"name": "john",
"age": 55,
"friends": ["tom", ""]
}"#;
let my_struct = serde_json::from_str::<Data>(json);
println!("{:?}", my_struct);
}
$ cargo run
Err(Error("\"\" does not satisfy Not<refined_type::rule::empty::EmptyRule<alloc::string::String>>", line: 4, column: 30))
Summary
By defining rules for each field, you can easily validate JSON data.
This is just one example of how you can use refined_type
to enhance your types.
Enjoy a wonderful type life!