JSONSchema那些事兒:基本概念

引子

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

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

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

 

 

而通過編輯表單錄入的數據,最終會在頁面中以 PHP 數組的形式填充和占位:

array(5) {

[0]=>

array(2) {

["text"]=>

string(6) "淘寶網"

["href"]=>

string(22) "https://www.taobao.com/"

},

}

從標簽函數到數據對象的運轉流程,可以用一張圖簡單予以概括:

 

 

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

從 描述數據格式、 構造模擬數據 的角度,這和我們要談的 JSON Schema 不謀而合。我們用 JSON 格式來重寫數據對象,應該是醬紫的:

[

{

"text": "淘寶網",

"href": "https://www.taobao.com/"

},

]

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

什麼是 Schema?

當我們在描述 文字鏈接 的時候,需要約定數據的組織方式,比如,需要知道有哪些字段,這些字段的取值如何表示等,這就是 JSON Schema 的來源。

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

{

"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 數據:

下面的三份數據,如果用空對象來校驗的話,都是符合要求的:

250

"我是一個字符串"

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

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

type 關鍵字

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

{ "type": "string" }

可以校驗通過:

"我是一個字符串"

無法校驗通過:

250

type 關鍵字也取值為其他數據類型,比如 object,array 等,當 type 為 object 類型時,properties 關鍵字是必需的,當 type 為 array 類型時,items 關鍵字是必需的。

於此同時,object 和 array 類型的引入使得數據結構可以支持無限級嵌套,也就突破瞭我們在引子中提到的,標簽函數描述過於扁平的問題。

title 和 description

title 和 description 關鍵字是描述性的,並不對數據具有約束作用,隻是用來對文檔作補充說明:

{

"title": "標題",

"description": "描述"

}

聲明 JSON Schema

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

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

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

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

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

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

簡單的例子

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

{

"$schema": "https://json-schema.org/draft-04/schema#",

"title": "TextLinks",

"description": "文字鏈接",

"type": "array"

}

其中,第一個維度為數組,而每個數組成員,又都是由 text 和 href 兩個字段構成的對象,分別表示鏈接的標題和地址。因此,描述可以擴充為:

{

"$schema": "https://json-schema.org/draft-04/schema#",

"title": "TextLinks",

"description": "文字鏈接",

"type": "array",

"items": {

"type": "object",

"properties": {

"text": {

"type": "string",

"title": "文字"

},

"href": {

"type": "string",

"title": "鏈接地址(URL)"

}

}

}

}

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

{

"$schema": "https://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 已經有瞭基本認知,也可能一頭霧水。沒有關系,更多細節,我們將在接下來的系列文章中娓娓道來。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *