为了解决页面模板和数据的分离问题。

JSON Schema 那些事儿:基本概念

2016/01/27 · HTML5 ·
JSON

原文出处: 淘宝前端团队(FED)-
邦彦   

威尼斯赌场手机版本 1

引子

在早期的淘宝 TMS
页面搭建系统中,为了解决页面模板和数据的分离问题,机智的先知们扩充了一系列灵活的
PHP
标签函数,得以将数据的定义从模板视图中解耦出来。以其中一个最为常用的函数为例:

JavaScript

_tms_custom(‘{“name”:”TextLinks”,”title”:”文字链接”,”group”:”文字链接”,”row”:”10″,”defaultRow”:”5″,”fields”:”text:文字:string,href:链接地址(URL):href”}’);

1
_tms_custom(‘{"name":"TextLinks","title":"文字链接","group":"文字链接","row":"10","defaultRow":"5","fields":"text:文字:string,href:链接地址(URL):href"}’);

当调用 _tms_custom(...) 函数并传入指定格式的 JSON
参数,交由翻译引擎处理后,会构建出这样的编辑表单:

威尼斯赌场手机版本 2

而通过编辑表单录入的数据,最终会在页面中以 PHP 数组的形式填充和占位:

JavaScript

array(5) { [0]=> array(2) { [“text”]=> string(6) “淘宝网”
[“href”]=> string(22) “http://www.taobao.com/” }, … }

1
2
3
4
5
6
7
8
9
10
array(5) {
[0]=>
array(2) {
["text"]=>
string(6) "淘宝网"
["href"]=>
string(22) "http://www.taobao.com/"
},
}

从标签函数到数据对象的运转流程,可以用一张图简单予以概括:

威尼斯赌场手机版本 3

这种模板和数据分离的方式,在早些年那是相当先进的。它用简单的语法,描述了模板所需的数据格式,还可以根据标签定义,直接构造出模拟数据,方便在开发阶段使用
“标签 + 模拟数据” 的方式调试页面。

描述数据格式构造模拟数据 的角度,这和我们要谈的 JSON
Schema 不谋而合。我们用 JSON 格式来重写数据对象,应该是酱紫的:

JavaScript

[ { “text”: “淘宝网”, “href”: “http://www.taobao.com/” }, … ]

1
2
3
4
5
6
7
[
{
    "text": "淘宝网",
    "href": "http://www.taobao.com/"
},
]

如果用 JSON Schema
语法描述这份数据,可以完全替代标签函数的方案。这也正是淘宝 TMS
页面搭建系统在数据这块的演化过程:即从使用标签函数定义数据的方式,转变为使用
JSON Schema 描述数据。

什么是 Schema?

当我们在描述 文字链接
的时候,需要约定数据的组织方式,比如,需要知道有哪些字段,这些字段的取值如何表示等,这就是
JSON Schema 的来源。

我们以 文字链接 为例,它对应的 JSON Schema 大概如此:

JavaScript

{ “type”: “object”, “properties”: { “text”: { “type”: “string”, “title”:
“文字” }, “href”: { “type”: “string”, “title”: “链接地址(URL)” } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"type": "object",
"properties": {
"text": {
"type": "string",
"title": "文字"
},
"href": {
"type": "string",
"title": "链接地址(URL)"
}
}
}

JSON Schema 定义了如何基于 JSON 格式描述 JSON
数据结构的规范,进而提供数据校验、文档生成和接口数据交互控制等一系列能力。它的特性和用途,可以大致归纳为以下几点:

1. 用于描述数据结构

在描述 JSON
数据时,如果数据本身的复杂度很高,高到三维四维,普通的标签函数已经无法表示这种层级结构了,而
JSON Schema 利用 objectarray
字段类型的反复嵌套,可以规避掉这个缺陷。

当然,除了键值等基本信息,规范层面还提供了丰富的关键词支持,如果想通过自定义扩展字段,解决特定场景的业务需求,也是非常方便的。

2. 用于构建人机可读的文档

计算机领域有个概念叫做自描述。所谓自描述,可以理解为:文档本身包含了自身与其他文档交互相关的描述信息,不需要其他的配置文件或者额外信息来描述。

而 JSON Schema
就是自描述的,它本身就是一份很完善的说明文档,字段的含义说明、该如何取值、格式的要求等都清晰明了。

3. 用于生成模拟数据

通过标签函数生成模拟数据,只能解决基本的格式要求。比如 string
类型的字段,模拟出来的数据,无非是一个随机字符串。

但在 JSON Schema
中,由于字段的描述不仅仅是类型,更多的约束条件,可以确保模拟数据更接近于真实数据。

4. 用于校验数据,实现自动化测试

接口数据的校验工作,往往依赖于测试代码逻辑和用例。如果用 JSON Schema
描述一个数据接口,就不需要再编写测试代码了,所有的逻辑都可以移植到 JSON
Schema 中维护。配合 jsvtv4
等二方校验工具,接口测试可以真正自动化。

基本约束

在 JSON Schema 的世界里,一个空对象,可以描述和校验任意形式的 JSON
数据:

JavaScript

{}

1
{}

下面的三份数据,如果用空对象来校验的话,都是符合要求的:

JavaScript

250 “我是一个字符串” {“code”: 200, “data”: “”, “message”: “呵呵”}

1
2
3
250
"我是一个字符串"
{"code": 200, "data": "", "message": "呵呵"}

当然,如果这么玩的话,JSON Schema 就完全没有意义了。

type 关键字

所以,我们需要使用 type 关键字,将 JSON Schema
限制为特定的数据类型。比如下面这个 JSON Schema
描述,只有字符串类型的数据,才能顺利通过校验:

JavaScript

{ “type”: “string” }

1
{ "type": "string" }

可以校验通过:

JavaScript

“我是一个字符串”

1
"我是一个字符串"

无法校验通过:

JavaScript

250

1
250

type 关键字也取值为其他数据类型,比如 objectarray 等,当 type
object 类型时,properties 关键字是必需的,当 typearray
类型时,items 关键字是必需的。

于此同时,objectarray
类型的引入使得数据结构可以支持无限级嵌套,也就突破了我们在引子中提到的,标签函数描述过于扁平的问题。

title 和 description

titledescription
关键字是描述性的,并不对数据具有约束作用,只是用来对文档作补充说明:

JavaScript

{ “title”: “标题”, “description”: “描述” }

1
2
3
4
{
"title": "标题",
"description": "描述"
}

声明 JSON Schema

考虑到 JSON Schema 文档本身也是 JSON 格式的,初识 JSON Schema
的人,不一定能将普通 JSON 和 JSON Schema 区分开来,于是草案提供了一个
$schema 关键字,专门用来声明当前文档是标准的 JSON Schema
文档,当然,这个关键词并不是必需的。

JavaScript

{ “$schema”: “http://json-schema.org/schema\#” }

1
{ "$schema": "http://json-schema.org/schema#" }

实际情况中,陈旧的 JSON Schema 文档可以仍然遵循旧的草案,所以,利用
$schema 也能够指明具体依赖的草案版本,规避草案演进可能带来的差异问题。

为了表示文档的唯一性,还可选指定一个 id 关键字,通常是一个具体的 URL
地址,比如:

JavaScript

{ “id”: “http://example.com/schemas/my\_schema.json” }

1
{ "id": "http://example.com/schemas/my_schema.json" }

在整个 JSON Schema 文档中,id 的取值威尼斯赌场手机版本一定是唯一的,就像 css 中的 id
一样在当前文档中是不可重复的。

简单的例子

还是以引子中提到的场景为例,尝试用 JSON Schema
语法描述标签函数,可以从一个基本轮廓开始:

JavaScript

{ “$schema”: “http://json-schema.org/draft-04/schema\#”, “title”:
“TextLinks”, “description”: “文字链接”, “type”: “array” }

1
2
3
4
5
6
{
"$schema": "http://json-schema.org/draft-04/schema#",
    "title": "TextLinks",
    "description": "文字链接",
    "type": "array"
}

其中,第一个维度为数组,而每个数组成员,又都是由 texthref
两个字段构成的对象,分别表示链接的标题和地址。因此,描述可以扩充为:

JavaScript

{ “$schema”: “http://json-schema.org/draft-04/schema\#”, “title”:
“TextLinks”, “description”: “文字链接”, “type”: “array”, “items”: {
“type”: “object”, “properties”: { “text”: { “type”: “string”, “title”:
“文字” }, “href”: { “type”: “string”, “title”: “链接地址(URL)” } } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"$schema": "http://json-schema.org/draft-04/schema#",
    "title": "TextLinks",
    "description": "文字链接",
    "type": "array",
    "items": {
     "type": "object",
     "properties": {
     "text": {
     "type": "string",
     "title": "文字"
     },
     "href": {
     "type": "string",
     "title": "链接地址(URL)"
     }
     }
    }
}

根据标签函数的定义,对数据行数的控制,还有 rowdefaultRow
两个附加约束,可以分别对应到 JSON Schema 规范中的最大条目限制 maxItems
和最小条目限制 minItems 两个关键字。那么,最终的数据描述就变成了:

JavaScript

{ “$schema”: “http://json-schema.org/draft-04/schema\#”, “title”:
“TextLinks”, “description”: “文字链接”, “type”: “array”, “items”: {
“type”: “object”, “properties”: { “text”: { “type”: “string”, “title”:
“文字” }, “href”: { “type”: “string”, “title”: “链接地址(URL)” } } },
“maxItems”: 10, “minItems”: 5 }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"$schema": "http://json-schema.org/draft-04/schema#",
    "title": "TextLinks",
    "description": "文字链接",
    "type": "array",
    "items": {
     "type": "object",
     "properties": {
     "text": {
     "type": "string",
     "title": "文字"
     },
     "href": {
     "type": "string",
     "title": "链接地址(URL)"
     }
     }
    },
    "maxItems": 10,
    "minItems": 5
}

好了,例子潦潦草草地讲完了,没有深入地展开,你可能对 JSON Schema
已经有了基本认知,也可能一头雾水。没有关系,更多细节,我们将在接下来的系列文章中娓娓道来。

相关资料

  • JSON Schema and Hyper-Schema
  • Schema and
    metadata
  • draft-zyp-json-schema-04

  • [1]: TMS 为淘宝内部运营活动系统。

    1 赞 2 收藏
    评论

威尼斯赌场手机版本 4

发表评论

电子邮件地址不会被公开。 必填项已用*标注