1. 程式人生 > >JSON Schema 那些事兒:基本概念

JSON Schema 那些事兒:基本概念

引子

在早期的淘寶 TMS 頁面搭建系統中,為了解決頁面模板和資料的分離問題,機智的先知們擴充了一系列靈活的 PHP 標籤函式,得以將資料的定義從模板檢視中解耦出來。以其中一個最為常用的函式為例:


1
_tms_custom('{"name":"TextLinks","title":"文字連結","group":"文字連結","row":"10","defaultRow":"5","fields":"text:文字:string,href:連結地址(URL):href"}');

當呼叫 _tms_custom(...) 函式並傳入指定格式的 JSON 引數,交由翻譯引擎處理後,會構建出這樣的編輯表單:

而通過編輯表單錄入的資料,最終會在頁面中以 PHP 陣列的形式填充和佔位:

1
2
3
4
5
6
7
8
9
10
array(5) {
[0]=>
array(2) {
["text"]=>
string(6) "淘寶網"
["href"]=>

},
...
}

從標籤函式到資料物件的運轉流程,可以用一張圖簡單予以概括:

這種模板和資料分離的方式,在早些年那是相當先進的。它用簡單的語法,描述了模板所需的資料格式,還可以根據標籤定義,直接構造出模擬資料,方便在開發階段使用 “標籤 + 模擬資料” 的方式除錯頁面。

描述資料格式構造模擬資料

的角度,這和我們要談的 JSON Schema 不謀而合。我們用 JSON 格式來重寫資料物件,應該是醬紫的:

1
2
3
4
5
6
7

如果用 JSON Schema 語法描述這份資料,可以完全替代標籤函式的方案。這也正是淘寶 TMS 頁面搭建系統在資料這塊的演化過程:即從使用標籤函式定義資料的方式,轉變為使用 JSON Schema 描述資料。

什麼是 Schema?

當我們在描述 文字連結 的時候,需要約定資料的組織方式,比如,需要知道有哪些欄位,這些欄位的取值如何表示等,這就是 JSON Schema 的來源。

我們以 文字連結 為例,它對應的 JSON Schema 大概如此:

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 資料:


1
{}

下面的三份資料,如果用空物件來校驗的話,都是符合要求的:

1
250

1
"我是一個字串"

1
{"code": 200, "data": "", "message": "呵呵"}

當然,如果這麼玩的話,JSON Schema 就完全沒有意義了。

type 關鍵字

所以,我們需要使用 type 關鍵字,將 JSON Schema 限制為特定的資料型別。比如下面這個 JSON Schema 描述,只有字串型別的資料,才能順利通過校驗:


1
{ "type": "string" }

可以校驗通過:

1
"我是一個字串"

無法校驗通過:

1
250

type 關鍵字也取值為其他資料型別,比如 objectarray 等,當 typeobject 型別時,properties 關鍵字是必需的,當 typearray 型別時,items 關鍵字是必需的。

於此同時,objectarray 型別的引入使得資料結構可以支援無限級巢狀,也就突破了我們在引子中提到的,標籤函式描述過於扁平的問題。

title 和 description

titledescription 關鍵字是描述性的,並不對資料具有約束作用,只是用來對文件作補充說明:


1
2
3
4
{
"title": "標題",
"description": "描述"
}

宣告 JSON Schema

考慮到 JSON Schema 文件本身也是 JSON 格式的,初識 JSON Schema 的人,不一定能將普通 JSON 和 JSON Schema 區分開來,於是草案提供了一個 $schema 關鍵字,專門用來聲明當前文件是標準的 JSON Schema 文件,當然,這個關鍵詞並不是必需的。


實際情況中,陳舊的 JSON Schema 文件可以仍然遵循舊的草案,所以,利用 $schema 也能夠指明具體依賴的草案版本,規避草案演進可能帶來的差異問題。

為了表示文件的唯一性,還可選指定一個 id 關鍵字,通常是一個具體的 URL 地址,比如:

在整個 JSON Schema 文件中,id 的取值一定是唯一的,就像 css 中的 id 一樣在當前文件中是不可重複的。

簡單的例子

還是以引子中提到的場景為例,嘗試用 JSON Schema 語法描述標籤函式,可以從一個基本輪廓開始:


1
2
3
4
5
6
{

"title": "TextLinks",
"description": "文字連結",
"type": "array"
}

其中,第一個維度為陣列,而每個陣列成員,又都是由 texthref 兩個欄位構成的物件,分別表示連結的標題和地址。因此,描述可以擴充為:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{

"title": "TextLinks",
"description": "文字連結",
"type": "array",
"items": {
"type": "object",
"properties": {
"text": {
"type": "string",
"title": "文字"
},
"href": {
"type": "string",
"title": "連結地址(URL)"
}
}
}
}

根據標籤函式的定義,對資料行數的控制,還有 rowdefaultRow 兩個附加約束,可以分別對應到 JSON Schema 規範中的最大條目限制 maxItems 和最小條目限制 minItems 兩個關鍵字。那麼,最終的資料描述就變成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{

"title": "TextLinks",
"description": "文字連結",
"type": "array",
"items": {
"type": "object",
"properties": {
"text": {
"type": "string",
"title": "文字"
},
"href": {
"type": "string",
"title": "連結地址(URL)"
}
}
},
"maxItems": 10,
"minItems": 5
}

好了,例子潦潦草草地講完了,沒有深入地展開,你可能對 JSON Schema 已經有了基本認知,也可能一頭霧水。沒有關係,更多細節,我們將在接下來的系列文章中娓娓道來。

相關資料



  • [1]: TMS 為淘寶內部運營活動系統。