Skip to content
kk edited this page Jun 29, 2018 · 1 revision

如何描述数据?

本质上,所有数据都可以用函数来描述。

比如,一个大于 0 的整数:

def validate_int_plus(value):
    assert isinstance(value, int), 'invalid number'
    assert value > 0, 'number must > 0'

又如,一个最大长度为 120 个字符的字符串:

def validate_str_maxlen_120(value):
    assert isinstance(value, str), 'invalid string'
    assert len(value) <= 120, 'string too long'

把这些函数分门别类,就有了各种 校验器

比如,可以指定最大值和最小值的整数校验器:

def int_validator(min, max):
    def validate(value):
        assert isinstance(value, int), 'invalid number'
        assert value >= min, f'number must >= {min}'
        assert value <= max, f'number must <= {max}'
    return validate

Schema 仅仅是校验器的一种表示方式。

如何表示校验器?

经过对比,我发现一种 渐进表示法 非常适合。

比如,整数校验器:

int

最小值为 0 的整数校验器:

int.min(0)

最小值为 0,最大值为 100 的整数校验器:

int.min(0).max(100)

它可以根据需要,不断地补充描述。

另外,如果参数值为 True,可以省略参数值:

int.optional(True) == int.optional

对于字典和列表,可以校验容器內的元素:

list( int.min(0).max(100) )

dict(
    key1=int.min(0).max(100),
    key2=str.maxlen(10),
)

用 Python 语法定义 Schema

因为 int, str, dict 等等在 Python 中已有特定的含义, 所以要给校验器名称加上 T. 前缀,例如:

T.int.min(0).max(100)
T.dict(
    key1=T.int.min(0).max(100),
    key2=T.str.maxlen(10),
)

也可以用 Python 类定义 Dict Schema:

@modelclass
class MyModel:
    key1 = T.int.min(0).max(100)
    key2 = T.str.maxlen(10)

用 JSON 语法定义 Schema

JSON 数据可以分为3种结构:

  • 映射:"名称/值"对的集合,也被理解为对象(object)或字典(dictionary)
  • 序列:有序列表,也被理解为数组
  • 标量:string number true false null

Schema 本身也是 JSON,也用这三种结构描述相应的数据,也因此称为 同构的JSON-Schema

映射结构用 $self 描述自身,其余 key 描述字典里的内容:

{
    "$self": "schema",
    "key": "schema"
}

序列结构用第一个元素描述自身,第二个元素描述序列里的内容:

["schema", Item]

序列结构也可以省略第一个元素,即只描述序列里的内容,不描述自身。

[Item]

标量结构用字符串描述自身:

"schema"

注:JSON 格式主要用于跨语言使用 Schema。

示例

这是实际数据

{
    "id": 1,
    "name": "A green door",
    "price": 12.50,
    "tags": ["home", "green"]
}

对应 Schema 的 Python 语法表示:

T.dict(
    id=T.int.desc('The unique identifier for a product'),
    name=T.str.desc('Name of the product'),
    price=T.float.exmin(0),
    tags=T.list(
        T.str.minlen(1)
    ).unique
)

用 Python 类定义的 Schema:

@modelclass
class Product:
    id = T.int.desc('The unique identifier for a product')
    name = T.str.desc('Name of the product')
    price = T.float.exmin(0)
    tags = T.list(
        T.str.minlen(1)
    ).unique

对应 Schema 的 JSON 语法表示:

{
    "$self": "dict",
    "id": "int.desc('The unique identifier for a product')",
    "name": "str.desc('Name of the product')",
    "price": "float.exmin(0)",
    "tags": [
        "list.unique",
        "str.minlen(1)"
    ]
}