use miko::extractor::{Json, ValidatedJson};
use miko::garde::Validate;
use miko::utoipa::ToSchema;
use miko::*;
use miko_macros::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Validate, ToSchema)]
struct CreateUserRequest {
#[garde(length(min = 3, max = 50))]
username: String,
#[garde(contains("@"))]
email: String,
#[garde(length(min = 8))]
password: String,
#[garde(range(min = 13, max = 120))]
age: u8,
}
#[derive(Debug, Serialize)]
struct UserResponse {
id: u64,
username: String,
email: String,
age: u8,
}
#[post("/users")]
async fn create_user(ValidatedJson(req): ValidatedJson<CreateUserRequest>) -> Json<UserResponse> {
println!("✅ Creating user: {:?}", req);
Json(UserResponse {
id: 1,
username: req.username,
email: req.email,
age: req.age,
})
}
#[post("/users/unvalidated")]
async fn create_user_unvalidated(Json(req): Json<CreateUserRequest>) -> Json<UserResponse> {
println!("⚠️ Creating user (unvalidated): {:?}", req);
Json(UserResponse {
id: 2,
username: req.username,
email: req.email,
age: req.age,
})
}
#[derive(Debug, Deserialize, Validate)]
struct Address {
#[garde(length(min = 1))]
street: String,
#[garde(length(min = 1))]
city: String,
#[garde(length(min = 2, max = 2))]
country_code: String,
}
#[derive(Debug, Deserialize, Validate)]
struct CreateCompanyRequest {
#[garde(length(min = 3, max = 100))]
name: String,
#[garde(contains("@"))]
contact_email: String,
#[garde(dive)] address: Address,
}
#[post("/companies")]
async fn create_company(ValidatedJson(req): ValidatedJson<CreateCompanyRequest>) -> String {
println!("✅ Creating company: {:?}", req);
format!("Company '{}' created successfully", req.name)
}
#[derive(Debug, Deserialize, Validate)]
struct UpdateProfileRequest {
#[garde(length(min = 1, max = 100))]
display_name: Option<String>,
#[garde(length(min = 1))]
website: Option<String>,
#[garde(length(max = 500))]
bio: Option<String>,
}
#[put("/profile")]
async fn update_profile(ValidatedJson(req): ValidatedJson<UpdateProfileRequest>) -> String {
println!("✅ Updating profile: {:?}", req);
"Profile updated successfully".to_string()
}
#[miko]
async fn main() {
tracing_subscriber::fmt::init();
println!("🚀 Validation Test Server");
println!("============================================================");
println!();
println!("测试端点:");
println!(" POST /users - 创建用户(自动验证)");
println!(" POST /users/unvalidated - 创建用户(无验证,对比用)");
println!(" POST /companies - 创建公司(嵌套验证)");
println!(" PUT /profile - 更新资料(可选字段验证)");
println!();
println!("============================================================");
println!("测试命令:");
println!();
println!("✅ 有效请求:");
println!(
r#"curl -X POST http://127.0.0.1:8080/users -H "Content-Type: application/json" -d '{{"username":"alice","email":"alice@example.com","password":"password123","age":25}}'"#
);
println!();
println!("❌ 用户名太短 (应该 >= 3):");
println!(
r#"curl -X POST http://127.0.0.1:8080/users -H "Content-Type: application/json" -d '{{"username":"ab","email":"alice@example.com","password":"password123","age":25}}'"#
);
println!();
println!("❌ 邮箱格式错误:");
println!(
r#"curl -X POST http://127.0.0.1:8080/users -H "Content-Type: application/json" -d '{{"username":"alice","email":"not-an-email","password":"password123","age":25}}'"#
);
println!();
println!("❌ 密码太短 (应该 >= 8):");
println!(
r#"curl -X POST http://127.0.0.1:8080/users -H "Content-Type: application/json" -d '{{"username":"alice","email":"alice@example.com","password":"123","age":25}}'"#
);
println!();
println!("❌ 年龄超出范围 (应该 13-120):");
println!(
r#"curl -X POST http://127.0.0.1:8080/users -H "Content-Type: application/json" -d '{{"username":"alice","email":"alice@example.com","password":"password123","age":150}}'"#
);
println!();
println!("✅ 嵌套验证:");
println!(
r#"curl -X POST http://127.0.0.1:8080/companies -H "Content-Type: application/json" -d '{{"name":"ACME Corp","contact_email":"info@acme.com","address":{{"street":"123 Main St","city":"New York","country_code":"US"}}}}'"#
);
println!();
println!("❌ 国家代码长度错误 (应该是 2 个字符):");
println!(
r#"curl -X POST http://127.0.0.1:8080/companies -H "Content-Type: application/json" -d '{{"name":"ACME Corp","contact_email":"info@acme.com","address":{{"street":"123 Main St","city":"New York","country_code":"USA"}}}}'"#
);
println!();
println!("✅ 可选字段验证:");
println!(
r#"curl -X PUT http://127.0.0.1:8080/profile -H "Content-Type: application/json" -d '{{"display_name":"Alice","website":"https://example.com","bio":"Hello world"}}'"#
);
println!();
println!("============================================================");
}