52 个版本 (19 个稳定版)

4.0.0 2023 年 5 月 13 日
4.0.0-rc.02023 年 2 月 20 日
3.6.1 2022 年 8 月 10 日
3.6.0 2021 年 2 月 20 日
0.1.0 2014 年 11 月 23 日

#78Rust 模式

Download history 59217/week @ 2024-03-14 62145/week @ 2024-03-21 67893/week @ 2024-03-28 73932/week @ 2024-04-04 77176/week @ 2024-04-11 80963/week @ 2024-04-18 80508/week @ 2024-04-25 87772/week @ 2024-05-02 83696/week @ 2024-05-09 82729/week @ 2024-05-16 90287/week @ 2024-05-23 107175/week @ 2024-05-30 100165/week @ 2024-06-06 96435/week @ 2024-06-13 85970/week @ 2024-06-20 93204/week @ 2024-06-27

401,037 次每月下载
38 个crate中使用 (29 个直接使用)

MIT 许可证

290KB
8K SLoC

什么是 Valico?

Build Status

Valico 是一个用于 JSON 对象的验证和转换工具,用 Rust 编写。它旨在作为各种类似 REST 的框架或其他需要从外部世界验证和转换 JSON 输入的工具的支持库。

Valico 有两个功能

  • DSL — 一组简单的验证器和转换器,灵感来自 [Grape]。它内置了对常见转换器、验证器的支持,并在出错时可以返回详细的错误信息。
  • JSON Schema — 基于 IETF 草案 v7 的 JSON Schema 实现。

参考资料

# Cargo.toml
valico = "2"

API 文档

JSON Schema

它通过了整个 JSON-Schema-Test-Suite,除了使用 unicode 偏旁对时远程引用和 maxLength/minLength,它还可以验证您的模式并解释其中存在的问题。

示例

extern crate serde_json;
extern crate valico;

use serde_json::Value;
use valico::json_schema;
use std::fs::File;

fn main() {
    let json_schema: Value = serde_json::from_reader(File::open("tests/schema/schema.json").unwrap()).unwrap();

    let mut scope = json_schema::Scope::new();
    let schema = scope.compile_and_return(json_v4_schema.clone(), false).unwrap();

    println!("Is valid: {}", schema.validate(&json_v4_schema).is_valid());
}

JSON Schema 构建器

Valico 提供了一个 valico::json_schema::schema(|scheme| { /* .. */ }) -> json::Json 函数,允许您使用简单的 DSL 生成您的方案。它允许您不使用字符串和原始 JSON 操作,还可以防止某些拼写和类型错误。

builder::schema(|s| {
    s.properties(|properties| {
        properties.insert("prop1", |prop1| {
            prop1.maximum(10f64, false);
        });
    });
    s.pattern_properties(|properties| {
        properties.insert("prop.*", |prop| {
            prop.maximum(1000f64, false);
        });
    });
    s.additional_properties_schema(|additional| {
        additional.maximum(5f64, false)
    });
})

待办事项:在此处添加更多关于 JSON Schema 的文档

DSL

基本用法

所有 Valico 东西都是通过 Builder 实例创建的。以下是一个简单的示例,展示了如何创建和设置 Builder

let params = Builder::build(|params| {
	params.req_nested("user", Builder::list(), |params| {
		params.req_typed("name", json_dsl::string());
		params.req_typed("friend_ids", json_dsl::array_of(json_dsl::u64()))
	});
});

后续的 params 实例可以用于通过其 process 方法处理一个或多个 JSON 对象,该方法的签名如下:fn process(&self, tree: &mut JsonObject) -> ValicoResult<()>

注意,如果需要强制转换,Valico 将会修改借用的 JSON 值。

示例

extern crate valico;
extern crate serde_json;

use valico::json_dsl;
use serde_json::{from_str, to_string_pretty};

fn main() {

    let params = json_dsl::Builder::build(|params| {
        params.req_nested("user", json_dsl::array(), |params| {
            params.req_typed("name", json_dsl::string());
            params.req_typed("friend_ids", json_dsl::array_of(json_dsl::u64()))
        });
    });

    let mut obj = from_str(r#"{"user": {"name": "Frodo", "friend_ids": ["1223"]}}"#).unwrap();

    let state = params.process(&mut obj, &None);
    if state.is_valid() {
        println!("Result object is {}", to_string_pretty(&obj).unwrap());
    } else {
        panic!("Errors during process: {:?}", state);
    }

}

您还可以查看 规格说明 以获取更多细节和示例。

验证和强制转换

您可以使用 Builder::build 块定义参数的验证和强制转换选项。参数可以是 可选的必需的。必需参数必须始终存在。可选参数可以省略。

当参数在 JSON 中存在时,所有验证和强制转换都会应用,如果出现问题,则会触发错误。

Builder

以下功能在 Builder 中可用,用于定义参数


// Parameter is required, no coercion
fn req_defined(&mut self, name: &str);

// Parameter is required, with coercion
fn req_typed(&mut self, name: &str, coercer: Box<Coercer>);

// Parameter is required, with coercion and nested checks
fn req_nested(&mut self, name: &str, coercer: Box<Coercer>, nest_def: |&mut Builder|);

// Parameter is required, setup with Param DSL
fn req(&mut self, name: &str, param_builder: |&mut Param|);

// Parameter is optional, no coercion
fn opt_defined(&mut self, name: &str);

// Parameter is optional, with coercion
fn opt_typed(&mut self, name: &str, coercer: Box<Coercer>);

// Parameter is optional, with coercion and nested checks
fn opt_nested(&mut self, name: &str, coercer: Box<Coercer>, nest_def: |&mut Builder|);

// Parameter is required, setup with Param DSL
fn opt(&mut self, name: &str, param_builder: |&mut Param|);

内置强制转换器

可用强制转换器列表

  • json_dsl::i64()
  • json_dsl::u64()
  • json_dsl::f64()
  • json_dsl::string()
  • json_dsl::boolean()
  • json_dsl::null()
  • json_dsl::array()
  • json_dsl::array_of()
  • json_dsl::encoded_array() — 用于字符串编码的数组,例如 "red,green,blue" -> ["red", "green", "blue"]
  • json_dsl::encoded_array_of() — 用于某些类型的字符串编码数组,例如 "1,2,3" -> [1, 2, 3]
  • json_dsl::object()

使用示例

let params = Builder::build(|params| {
    params.req_typed("id", json_dsl::u64());
    params.req_typed("name", json_dsl::string());
    params.opt_typed("is_active", json_dsl::boolean());
    params.opt_typed("tags", json_dsl::array_of(json_dsl::strings()));
});

嵌套处理

您可以指定用于 列表对象 的嵌套处理的规则

let params = Builder::build(|params| {
    params.req_nested("user", json_dsl::object(), |params| {
        params.req_typed("name", json_dsl::string());
        params.opt_typed("is_active", json_dsl::boolean());
        params.opt_typed("tags", json_dsl::array_of(json_dsl::strings()));
    });
});

let params = Builder::build(|params| {
    params.req_nested("users", Builder::list(), |params| {
        params.req_typed("name", json_dsl::string());
        params.opt_typed("is_active", json_dsl::boolean());
        params.opt_typed("tags", json_dsl::array_of(json_dsl::strings()));
    });
});

Valico 中的嵌套级别不受限制。

使用 JSON 模式进行验证

DSL 允许在 Builder 级别和 Param 级别使用 JSON 模式验证来验证对象

let params = json_dsl::Builder::build(|params| {
    params.req("a", |a| {
        a.schema(|schema| {
            schema.integer();
            schema.maximum(10f64, false);
        })
    });
});

注意,JSON 模式在强制转换之后验证对象

let mut params = json_dsl::Builder::build(|params| {
    params.req("a", |a| {
        a.coerce(json_dsl::u64());
        a.schema(|schema| {
            schema.maximum(10f64, false);
        })
    });
});

在处理之前,请勿忘记创建 json_schema::Scope

let mut scope = json_schema::Scope::new();
params.build_schemes(&mut scope).unwrap();

参数 DSL

您可以使用 DSL 块以更灵活的方式设置参数

let params = Builder::build(|params| {
    params.req("user", |user| {
        user.desc("Parameter is used to create new user");
        user.coerce(json_dsl::object());

        // this allows null to be a valid value
        user.allow_null();

        user.nest(|params| {
            params.req_typed("name", json_dsl::string());
            params.opt("kind", |kind| {
                kind.coerce(json_dsl::string());

                // optional parameters can have default values
                kind.default("simeple_user".to_string())
            });
        });
    });
});

参数验证

DSL 支持几种参数验证。它们被认为是过时的,并可能在未来被 JSON 模式验证所取代。

allow_values

参数可以使用 allow_values 限制为特定的值集

let params = Builder::build(|params| {
    params.req("kind", |kind| {
        kind.coerce(json_dsl::string());
        kind.allow_values(&["circle".to_string(), "square".to_string()]);
    })
})
reject_values

可以使用 reject_values 拒绝某些值

let params = Builder::build(|params| {
    params.req("user_role", |kind| {
        kind.coerce(json_dsl::string());
        kind.reject_values(&["admin".to_string(), "manager".to_string()]);
    })
})
regex

可以使用 Regex 测试字符串值

let params = Builder::build(|params| {
    params.req("nickname", |a| {
        a.coerce(json_dsl::string());

        // force all nicknames to start with "Amazing"
        a.regex(regex!("^Amazing"));
    })
});
validate_with

有时使用自定义函数作为验证器很有用

let params = Builder::build(|params| {
    params.req("pushkin_birthday", |a| {
        a.coerce(json_dsl::u64());

        fn guess(val: &Json) -> Result<(), String> {
            if *val == 1799u.to_json() {
                Ok(())
            } else {
                Err("No!".to_string())
            }
        }

        a.validate_with(guess);
    });
});
validate

可以使用自定义验证器。文档正在编写中。

Builder 验证

可以在 Builder DSL 块中指定一些验证器来验证一组参数。

mutually_exclusive

可以将参数定义为互斥的,以确保它们不会同时存在于请求中。

let params = Builder::build(|params| {
    params.opt_defined("vodka");
    params.opt_defined("beer");

    params.mutually_exclusive(&["vodka", "beer"]);
});

可以定义多个集合

let params = Builder::build(|params| {
    params.opt_defined("vodka");
    params.opt_defined("beer");
    params.mutually_exclusive(&["vodka", "beer"]);

    params.opt_defined("lard");
    params.opt_defined("jamon");
    params.mutually_exclusive(&["lard", "jamon"]);
});

警告:永远不要使用任何必需参数定义互斥集合。两个互斥的必需参数将意味着参数永远无效。一个必需参数与一个可选参数互斥将意味着后者永远无效。

exactly_one_of

参数可以定义为 'exactly_one_of',确保恰好选择一个参数。

let params = Builder::build(|params| {
    params.opt_defined("vodka");
    params.opt_defined("beer");
    params.exactly_one_of(["vodka", "beer"]);
});
at_least_one_of

参数可以定义为 'at_least_one_of',确保至少选择一个参数。

let params = Builder::build(|params| {
    params.opt_defined("vodka");
    params.opt_defined("beer");
    params.opt_defined("wine");
    params.exactly_one_of(["vodka", "beer", "wine"]);
});
validate_with

有时使用自定义函数作为验证器很有用

let params = Builder::build(|params| {
    params.req_defined("monster_name");

    fn validate_params(_: &JsonObject) -> Result<(),String> {
        Err("YOU SHALL NOT PASS".to_string())
    }

    params.validate_with(validate_params);
});
validate

可以使用自定义验证器。文档正在编写中。

为其他目标构建

Web Assembly

对于 WebAssembly,启用 js 功能

# Cargo.toml
valico = { version = "2", features = ["js"] }

依赖

~9-17MB
~276K SLoC