JSON 是什麼
JSON,全稱 JavaScript Object Notation. 是 JS 的資料結構的子集。相信大家對 JSON 也非常熟悉了。JSON 一共只有六種資料結構,這裡列舉他們在 JS 和 Python 中的叫法以及在 JSON 中的例子:
JS | Python3 | JSON |
---|---|---|
string | string | "ABC" |
number | int/float | 123 -1.23 |
boolean | bool | true false |
null | None | null |
object | dictnu | {"key": "value"} |
array | list | ["ABC", 123, true] |
由於 JSON 是 JS 語法的子集,所以下文中我都會使用 JS 的稱呼。
得益於 JSON 極致的簡單和 JS 的廣泛使用,JSON 很快流行了起來。但是簡單也有簡單的壞處,人們逐漸發現 JSON 缺少一些必要的功。
JSON Schema 是什麼?
當前後端使用 JSON 通訊的時候,雙方需要驗證 JSON 的資料格式,比如驗證 array 的長度、number 的大小、甚至於類似 object 中有某兩個屬性不能並存等等要求。當然這些規則都可以使用程式碼進行驗證,但是這樣寫起來太繁瑣了,所以為了描述並校驗 JSON 的格式,JSON Schema 誕生了。
這裡有一個非常簡單的 JSON Schema 的例子:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"age": {
"type": "integer",
"minimum": 0,
"exclusiveMinimum": false,
},
"telephone": {
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}
},
"required": ["name", "email"],
"additionalProperties": false
}
複製程式碼
上面這個 JSON 描述了這樣的一個 JSON:
- 型別是 object
- 有四個屬性:
- name:
- 型別為 string
- email:
- 型別為 string
- Age:
- 型別為整數
- 這個整數要大於等於 0
- telephone:
- 型別為 string
- 需要符合這個正規表示式
- name:
- 上面這四個屬性中必須出現有的 name 和 email,剩下的兩個是可選的
- 除了這四個屬性外,不允許出現其他屬性
比如說,這樣的一個 JSON 就符合這些要求:
{
"name": "Sherlock Holmes",
"email": "sherlock@gmail.com",
"age": 164
}
複製程式碼
可以看到,JSON Schema 本身也是一個 JSON。同一個 JSON,同一個世界前後端都能看懂,那麼的話這個 JSON Schema 就既可以作為執行程式碼,又可以作為文件。這種統一確保了程式碼和文件不會脫節,省去了寫文件的功夫。畢竟程式設計師最討厭的就是沒有文件的程式碼和寫文件了。
Understanding JSON Schema
在這裡,我強烈推薦閱讀 Understanding JSON Schema,以至於我要專門寫一章來介紹它。這是一個非常適合初學者的教程,有著及其清晰的例子。雖然截止寫稿時其版本還停留在 draft-04,不過瑕不掩瑜,依然是我心中最優秀的 JSON Schema 教程。
在這裡列一下 Understanding JSON Schema 的大綱,方便查漏補缺:
- Type-specific keywords
string
minLength
maxLength
pattern
- Numeric types
- types:
integer
,number
multipleOf
- range:
minimum
,exclusiveMinimum
,maximum
,exclusiveMaximum
- types:
object
properties
additionalProperties
required
- size:
minProperties
,maxProperties
dependencies
patternProperties
array
items
- length:
minItems
,maxItems
uniqueItems
boolean
null
- Generic keywords
- Metadata:
title
,description
,default
- Enumerated values:
enum
- Metadata:
- Combining schemas
allOf
anyOf
oneOf
not
- The
$schema
keyword - Regular Expressions
版本
截止到今天,JSON Schema 一共有 7 個版本,最新的是 draft-07。不同版本之間並不(完全)相容,所以最佳實踐是在寫 JSON Schema 的時候使用 $schema
關鍵字標記當前使用的是哪個規範。
下面舉個例子,展示了 draft-04 和 draft-06 中「大於」和「大於等於」寫法:
大於:
{
"$schema": "https://json-schema.org/draft-06/schema#",
"type": "number",
"exclusiveMinimum": 0
}
複製程式碼
{
"$schema": "https://json-schema.org/draft-04/schema#",
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
}
複製程式碼
大於等於:
{
"$schema": "https://json-schema.org/draft-06/schema#",
"type": "number",
"minimum": 0
}
複製程式碼
{
"$schema": "https://json-schema.org/draft-04/schema#",
"type": "number",
"minimum": 0,
"exclusiveMinimum": false
}
複製程式碼
注:在 draft-04 中,exclusiveMinimum
的預設值就是 false
,所以可以不寫。
在 draft-04 中,exclusiveMinimum
的值是 boolean
,draft-06 中改成了 number
。在相同含義的情況下,新版的寫法的確更加簡潔。
關於不同版本之間的區別可以檢視官網的 Migrating from older drafts 一節。
總結
JSON Schema 作為一個驗證 JSON 的通用語法,我認為它成功完成了自己的任務。雖然有一些諸如可讀性不高,寫法繁瑣的缺點,但是我認為這些都是必要的妥協。