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
10array(5) {
[0]=>
array(2) {
["text"]=>
string(6) "淘寶網"
["href"]=>
},
...
}
從標籤函式到資料物件的運轉流程,可以用一張圖簡單予以概括:
這種模板和資料分離的方式,在早些年那是相當先進的。它用簡單的語法,描述了模板所需的資料格式,還可以根據標籤定義,直接構造出模擬資料,方便在開發階段使用 “標籤 + 模擬資料”
的方式除錯頁面。
從 描述資料格式、 構造模擬資料
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 利用 object
和 array
欄位型別的反覆巢狀,可以規避掉這個缺陷。
當然,除了鍵值等基本資訊,規範層面還提供了豐富的關鍵詞支援,如果想通過自定義擴充套件欄位,解決特定場景的業務需求,也是非常方便的。
2. 用於構建人機可讀的文件
計算機領域有個概念叫做自描述。所謂自描述,可以理解為:文件本身包含了自身與其他文件互動相關的描述資訊,不需要其他的配置檔案或者額外資訊來描述。
而 JSON Schema 就是自描述的,它本身就是一份很完善的說明文件,欄位的含義說明、該如何取值、格式的要求等都清晰明瞭。
3. 用於生成模擬資料
通過標籤函式生成模擬資料,只能解決基本的格式要求。比如 string
型別的欄位,模擬出來的資料,無非是一個隨機字串。
但在 JSON Schema 中,由於欄位的描述不僅僅是型別,更多的約束條件,可以確保模擬資料更接近於真實資料。
4. 用於校驗資料,實現自動化測試
介面資料的校驗工作,往往依賴於測試程式碼邏輯和用例。如果用 JSON Schema 描述一個數據介面,就不需要再編寫測試程式碼了,所有的邏輯都可以移植到 JSON Schema 中維護。配合 jsv
、tv4
等二方校驗工具,介面測試可以真正自動化。
基本約束
在 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
關鍵字也取值為其他資料型別,比如 object
,array
等,當 type
為 object
型別時,properties
關鍵字是必需的,當 type
為 array
型別時,items
關鍵字是必需的。
於此同時,object
和 array
型別的引入使得資料結構可以支援無限級巢狀,也就突破了我們在引子中提到的,標籤函式描述過於扁平的問題。
title 和 description
title
和 description
關鍵字是描述性的,並不對資料具有約束作用,只是用來對文件作補充說明:
1 | { |
宣告 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 | { |
其中,第一個維度為陣列,而每個陣列成員,又都是由 text
和 href
兩個欄位構成的物件,分別表示連結的標題和地址。因此,描述可以擴充為:
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)"
}
}
}
}
根據標籤函式的定義,對資料行數的控制,還有 row
和 defaultRow
兩個附加約束,可以分別對應到 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 為淘寶內部運營活動系統。