Rust近端数据校验宏库near-schema-checker-macro的使用,实现高效Schema验证与类型安全的Rust开发

Rust近端数据校验宏库near-schema-checker-macro的使用,实现高效Schema验证与类型安全的Rust开发

near-schema-checker-macro是一个用于NEAR协议开发的Rust宏库,它提供了高效的Schema验证和类型安全开发支持。

安装

在项目目录中运行以下Cargo命令:

cargo add near-schema-checker-macro

或在Cargo.toml中添加以下行:

near-schema-checker-macro = "0.30.3"

使用示例

以下是一个使用near-schema-checker-macro进行数据验证的完整示例:

use near_schema_checker_macro::near_schema;

// 定义一个带有Schema验证的结构体
#[near_schema]
#[derive(Debug)]
struct UserProfile {
    #[validate(length(min = 3, max = 32))]
    username: String,
    
    #[validate(range(min = 18, max = 120))]
    age: u8,
    
    #[validate(email)]
    email: String,
    
    #[validate(custom = "validate_timestamp")]
    created_at: u64,
}

// 自定义验证函数
fn validate_timestamp(timestamp: &u64) -> Result<(), String> {
    if *timestamp > 1609459200 { // 2021-01-01
        Ok(())
    } else {
        Err("Timestamp too old".to_string())
    }
}

fn main() {
    // 正确数据示例
    let valid_profile = UserProfile {
        username: "alice".to_string(),
        age: 25,
        email: "alice@example.com".to_string(),
        created_at: 1640995200, // 2022-01-01
    };
    
    // 验证并打印结果
    match valid_profile.validate() {
        Ok(_) => println!("Profile is valid!"),
        Err(err) => println!("Validation error: {}", err),
    }
    
    // 错误数据示例
    let invalid_profile = UserProfile {
        username: "a".to_string(), // 太短
        age: 121, // 超出范围
        email: "invalid-email".to_string(), // 无效邮箱
        created_at: 1577836800, // 2020-01-01
    };
    
    // 验证并打印所有错误
    if let Err(errors) = invalid_profile.validate() {
        for error in errors {
            println!("Field '{}': {}", error.field, error.message);
        }
    }
}

完整示例

以下是near-schema-checker-macro的另一个完整示例,展示如何验证更复杂的数据结构:

use near_schema_checker_macro::near_schema;
use serde::{Serialize, Deserialize};

// 定义带验证的子结构体
#[near_schema]
#[derive(Debug, Serialize, Deserialize)]
struct Address {
    #[validate(length(min = 5, max = 100))]
    street: String,
    
    #[validate(regex = r"^[A-Z]{2}$")]
    state: String,
    
    #[validate(range(min = 1000, max = 99999))]
    zip_code: u32,
}

// 定义主结构体
#[near_schema]
#[derive(Debug, Serialize, Deserialize)]
struct BusinessProfile {
    #[validate(length(min = 2, max = 50))]
    name: String,
    
    #[validate(custom = "validate_tax_id")]
    tax_id: String,
    
    #[validate]
    address: Address,
    
    #[validate(items)]
    employees: Vec<Employee>,
}

// 定义员工结构体
#[near_schema]
#[derive(Debug, Serialize, Deserialize)]
struct Employee {
    #[validate(length(min = 3, max = 50))]
    name: String,
    
    #[validate(range(min = 18, max = 70))]
    age: u8,
    
    #[validate(email)]
    email: String,
}

// 自定义税号验证函数
fn validate_tax_id(tax_id: &str) -> Result<(), String> {
    if tax_id.len() == 10 && tax_id.chars().all(char::is_alphanumeric) {
        Ok(())
    } else {
        Err("Tax ID must be 10 alphanumeric characters".to_string())
    }
}

fn main() {
    // 创建有效商业资料
    let valid_business = BusinessProfile {
        name: "Tech Corp".to_string(),
        tax_id: "ABC123XYZ9".to_string(),
        address: Address {
            street: "123 Main St".to_string(),
            state: "NY".to_string(),
            zip_code: 10001,
        },
        employees: vec![
            Employee {
                name: "Alice Smith".to_string(),
                age: 30,
                email: "alice@techcorp.com".to_string(),
            },
            Employee {
                name: "Bob Johnson".to_string(),
                age: 28,
                email: "bob@techcorp.com".to_string(),
            },
        ],
    };
    
    // 验证有效数据
    match valid_business.validate() {
        Ok(_) => println!("Business profile is valid!"),
        Err(err) => println!("Validation error: {}", err),
    }
    
    // 创建无效商业资料
    let invalid_business = BusinessProfile {
        name: "T".to_string(), // 名称太短
        tax_id: "123".to_string(), // 无效税号
        address: Address {
            street: "a".to_string(), // 街道太短
            state: "New York".to_string(), // 州代码太长
            zip_code: 999999, // 邮编超出范围
        },
        employees: vec![
            Employee {
                name: "A".to_string(), // 名字太短
                age: 17, // 年龄太小
                email: "invalid".to_string(), // 无效邮箱
            },
        ],
    };
    
    // 验证并打印所有错误
    if let Err(errors) = invalid_business.validate() {
        for error in errors {
            println!("Validation error in field '{}': {}", error.field, error.message);
        }
    }
}

特性

  1. 类型安全验证:通过Rust的类型系统确保数据结构的正确性
  2. 丰富的验证规则:包括长度、范围、格式等多种验证条件
  3. 自定义验证:支持开发者定义自己的验证逻辑
  4. 高效编译时检查:宏在编译时展开,减少运行时开销
  5. 嵌套验证:支持验证嵌套的结构体和集合类型

许可证

本项目采用双许可证:

  • MIT
  • Apache-2.0

1 回复

以下是基于您提供的内容整理的完整示例demo,展示了near-schema-checker-macro库的各种用法:

基础用法示例

use near_schema_checker_macro::schema;
use serde_json::json;

// 1. 定义基本Schema
#[schema]
struct User {
    id: u64,
    username: String,
    email: String,
    age: Option<u8>,
    is_active: bool,
}

fn basic_usage() {
    // 2. 数据验证
    let user_data = json!({
        "id": 123,
        "username": "rustacean",
        "email": "user@example.com",
        "age": 30,
        "is_active": true
    }).to_string();

    let user: User = near_schema_checker_macro::from_str(&user_data).unwrap();
    println!("Validated user: {:?}", user);
}

嵌套结构和高级验证示例

// 3. 嵌套结构验证
#[schema]
struct Post {
    id: u64,
    title: String,
    content: String,
    author: User,  // 嵌套使用User结构
    tags: Vec<String>,
}

// 4. 自定义验证规则
#[schema]
struct Product {
    #[schema(min = 0.01)]  // 价格最小0.01
    price: f64,
    
    #[schema(max_length = 100)]  // 名称最大长度100
    name: String,
    
    #[schema(regex = "^[A-Z]{2}\\d{4}$")]  // SKU格式要求
    sku: String,
}

fn advanced_usage() {
    let post_data = json!({
        "id": 1,
        "title": "Rust Schema Validation",
        "content": "This is a post...",
        "author": {
            "id": 123,
            "username": "rustacean",
            "email": "user@example.com",
            "is_active": true
        },
        "tags": ["rust", "macro"]
    }).to_string();

    let post: Post = near_schema_checker_macro::from_str(&post_data).unwrap();
    println!("Validated post: {:?}", post);
}

枚举和集合验证示例

// 5. 枚举类型支持
#[schema]
enum AccountStatus {
    Active,
    Inactive,
    Suspended,
}

#[schema]
struct Account {
    id: u64,
    status: AccountStatus,
    last_login: Option<String>,
}

// 6. 集合验证
#[schema]
struct Order {
    id: u64,
    #[schema(min_items = 1)]  // 至少1个订单项
    items: Vec<String>,
    #[schema(unique_items = true)]  // 标签必须唯一
    tags: Vec<String>,
}

fn enum_and_collections() {
    let account_data = json!({
        "id": 1,
        "status": "Active",
        "last_login": "2023-01-01"
    }).to_string();

    let account: Account = near_schema_checker_macro::from_str(&account_data).unwrap();
    println!("Validated account: {:?}", account);
}

完整Web应用示例

use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use near_schema_checker_macro::schema;

#[schema]
struct RegisterRequest {
    username: String,
    #[schema(min_length = 8)]
    password: String,
    #[schema(email)]
    email: String,
}

async fn register(user: web::Json<RegisterRequest>) -> impl Responder {
    // 数据已经通过Schema验证
    HttpResponse::Ok().json("Registration successful")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(
                web::resource("/register")
                    .route(web::post().to(register))
            )
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

性能优化示例

use std::fs::File;
use once_cell::sync::Lazy;

#[schema]
struct Config {
    #[schema(default = "localhost")]
    host: String,
    #[schema(default = 8080)]
    port: u16,
}

// 重用已解析的Schema验证器
static CONFIG_VALIDATOR: Lazy<Config> = Lazy::new(|| {
    let file = File::open("config.json").unwrap();
    near_schema_checker_macro::from_reader(file).unwrap()
});

fn get_config() -> &'static Config {
    &CONFIG_VALIDATOR
}

错误处理示例

fn handle_errors() {
    let invalid_data = r#"
        {
            "id": "not_a_number",  // 错误的类型
            "username": "user",
            "email": "invalid-email",
            "is_active": true
        }
    "#;

    match near_schema_checker_macro::from_str::<User>(invalid_data) {
        Ok(user) => println!("Valid user: {:?}", user),
        Err(e) => {
            println!("Validation failed:");
            println!("- Field: {}", e.field());
            println!("- Error: {}", e.message());
            println!("- Expected: {}", e.expected());
        }
    }
}

这些示例完整展示了near-schema-checker-macro库的主要功能,包括基础数据结构验证、嵌套结构、自定义验证规则、枚举支持、集合验证以及在Web应用和配置文件中的实际应用场景。

回到顶部