#[path = "support.rs"]
mod support;
use noyalib::ValidatedValidator;
use serde::Deserialize;
use validator::Validate;
#[derive(Debug, Deserialize, Validate)]
#[allow(dead_code)]
struct UserAccount {
#[validate(email)]
email: String,
#[validate(length(min = 3, max = 32))]
username: String,
#[validate(range(min = 13, max = 130))]
age: u8,
#[validate(url)]
website: String,
}
#[derive(Debug, Deserialize, Validate)]
#[allow(dead_code)]
struct ApiKey {
#[validate(length(equal = 40))]
token: String,
#[validate(range(min = 1, max = 86_400))]
ttl_seconds: u32,
}
fn main() {
support::header("validator — declarative validation (Actix / Axum stack)");
support::task_with_output("Valid user account passes every rule", || {
let yaml = "
email: alice@example.com
username: alice
age: 30
website: https://alice.example.com
";
let cfg: ValidatedValidator<UserAccount> = noyalib::from_str(yaml).unwrap();
vec![
format!("email = {}", cfg.email),
format!("username = {}", cfg.username),
format!("age = {}", cfg.age),
format!("website = {}", cfg.website),
]
});
support::task_with_output("Malformed email rejected by `validate(email)`", || {
let yaml = "
email: not-an-email
username: alice
age: 30
website: https://alice.example.com
";
let res: Result<ValidatedValidator<UserAccount>, _> = noyalib::from_str(yaml);
match res {
Ok(_) => vec!["unexpected: parse succeeded".into()],
Err(e) => vec![format!("error: {e}")],
}
});
support::task_with_output("Out-of-range age rejected", || {
let yaml = "
email: bob@example.com
username: bob
age: 5
website: https://bob.example.com
";
let res: Result<ValidatedValidator<UserAccount>, _> = noyalib::from_str(yaml);
match res {
Ok(_) => vec!["unexpected: parse succeeded".into()],
Err(e) => vec![format!("error: {e}")],
}
});
support::task_with_output("Token of wrong length rejected", || {
let yaml = "
token: short
ttl_seconds: 3600
";
let res: Result<ValidatedValidator<ApiKey>, _> = noyalib::from_str(yaml);
match res {
Ok(_) => vec!["unexpected: parse succeeded".into()],
Err(e) => vec![format!("error: {e}")],
}
});
support::task_with_output("Correctly-shaped token + sane TTL passes", || {
let yaml = "
token: 0123456789abcdef0123456789abcdef01234567
ttl_seconds: 3600
";
let cfg: ValidatedValidator<ApiKey> = noyalib::from_str(yaml).unwrap();
vec![
format!("token = {}…", &cfg.token[..8]),
format!("ttl_seconds = {}", cfg.ttl_seconds),
]
});
println!();
println!(" `validator` is the idiomatic choice for HTTP-handler");
println!(" payloads in Axum / Actix / Rocket. Pair it with noyalib's");
println!(" `ValidatedValidator<T>` and a YAML config request body");
println!(" is checked the same way the corresponding JSON one is.");
support::footer();
}