JSON Schema 驗證:權威指南
JSON Schema 是一套用於註解和驗證 JSON 文件的詞彙規範。它為你的資料提供了一份契約——定義資料應該具備什麼形狀、接受什麼型別,以及哪些欄位是必填的。如果你的工作涉及 API、設定檔或任何結構化資料,JSON Schema 是你不可或缺的利器。
為什麼要使用 JSON Schema?
沒有驗證的 JSON 資料就像一張萬用牌。你可能收到一個字串格式的 age 欄位、缺少的 email,或格式錯誤的日期。JSON Schema 在邊界處攔截這些問題,防止錯誤資料在系統中擴散。
主要優勢:
- API 契約強制執行:自動驗證請求和回應內容
- 文件化:Schema 本身就是資料結構的活文件
- 程式碼產生:工具可以從 JSON Schema 產生型別、表單和資料庫結構
- 測試:驗證測試資料和模擬資料是否符合 Schema
基本 Schema 結構
每個 JSON Schema 都以幾個標準屬性開始:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/user.schema.json",
"title": "User",
"description": "A registered user in the system",
"type": "object",
"properties": {
"id": { "type": "integer", "minimum": 1 },
"name": { "type": "string", "minLength": 1, "maxLength": 100 },
"email": { "type": "string", "format": "email" },
"age": { "type": "integer", "minimum": 0, "maximum": 150 }
},
"required": ["id", "name", "email"]
}
使用我們的 JSON 格式化工具 美化你的 Schema,以便在分享給團隊前提高可讀性。
型別約束
JSON Schema 支援六種基本型別:
| 型別 | 說明 | 範例 |
|---|---|---|
string | 文字資料 | "hello" |
number | 任何數值 | 3.14 |
integer | 僅限整數 | 42 |
boolean | 布林值 | true |
array | 有序列表 | [1, 2, 3] |
object | 鍵值對 | {"key": "value"} |
null | 空值 | null |
字串約束
{
"type": "string",
"minLength": 1,
"maxLength": 255,
"pattern": "^[A-Za-z0-9]+$",
"format": "email"
}
內建格式包括:email、uri、date、date-time、ipv4、ipv6、uuid 和 hostname。
數值約束
{
"type": "number",
"minimum": 0,
"maximum": 100,
"exclusiveMinimum": 0,
"multipleOf": 0.01
}
陣列驗證
陣列可以驗證其項目、長度和唯一性:
{
"type": "array",
"items": { "type": "string", "format": "email" },
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}
對於元組驗證(固定長度陣列,每個位置有特定型別):
{
"type": "array",
"prefixItems": [
{ "type": "number" },
{ "type": "string" },
{ "type": "boolean" }
],
"items": false
}
物件驗證
物件支援屬性驗證、必填欄位和額外屬性控制:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"role": { "enum": ["admin", "editor", "viewer"] }
},
"required": ["name", "role"],
"additionalProperties": false
}
將 additionalProperties 設為 false 是嚴格模式,會拒絕 Schema 中未定義的任何屬性。這對 API 特別有用,可以捕捉欄位名稱的拼寫錯誤。
組合關鍵字
JSON Schema 支援使用邏輯運算子組合 Schema:
allOf(AND)
資料必須對所有子 Schema 有效:
{
"allOf": [
{ "$ref": "#/$defs/baseUser" },
{ "properties": { "role": { "const": "admin" } } }
]
}
oneOf(XOR)
資料必須恰好對一個子 Schema 有效:
{
"oneOf": [
{ "properties": { "type": { "const": "email" }, "email": { "type": "string" } } },
{ "properties": { "type": { "const": "phone" }, "phone": { "type": "string" } } }
]
}
anyOf(OR)
資料必須至少對一個子 Schema 有效。
條件驗證
if/then/else 關鍵字實現條件驗證:
{
"type": "object",
"properties": {
"country": { "type": "string" },
"postalCode": { "type": "string" }
},
"if": {
"properties": { "country": { "const": "US" } }
},
"then": {
"properties": { "postalCode": { "pattern": "^[0-9]{5}(-[0-9]{4})?$" } }
},
"else": {
"properties": { "postalCode": { "pattern": "^[A-Z0-9 -]+$" } }
}
}
參考與重用
使用 $ref 參考可重用的定義:
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["street", "city", "country"]
}
},
"type": "object",
"properties": {
"billingAddress": { "$ref": "#/$defs/address" },
"shippingAddress": { "$ref": "#/$defs/address" }
}
}
實際驗證
JavaScript (Ajv)
const Ajv = require('ajv');
const ajv = new Ajv();
const validate = ajv.compile(schema);
const valid = validate(data);
if (!valid) console.log(validate.errors);
Python (jsonschema)
from jsonschema import validate, ValidationError
try:
validate(instance=data, schema=schema)
except ValidationError as e:
print(f"Validation error: {e.message}")
如需在不設定開發環境的情況下快速驗證,可以將你的 JSON 和 Schema 貼到我們的 JSON 驗證工具 中。
實際範例:API 回應 Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"status": { "enum": ["success", "error"] },
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"createdAt": { "type": "string", "format": "date-time" }
},
"required": ["id", "name"]
}
},
"pagination": {
"type": "object",
"properties": {
"page": { "type": "integer", "minimum": 1 },
"perPage": { "type": "integer", "minimum": 1, "maximum": 100 },
"total": { "type": "integer", "minimum": 0 }
}
}
},
"required": ["status", "data"]
}
常見問題
JSON Schema draft-07 和 2020-12 有什麼差別?
Draft 2020-12 引入了多項改進:prefixItems 取代了 items 的元組形式,$dynamicRef 實現了更靈活的參考機制,詞彙支援允許自訂擴展。新專案建議使用 2020-12。如需與舊工具相容,draft-07 仍然廣泛支援。
JSON Schema 可以驗證字串欄位中的巢狀 JSON 嗎?
不能直接驗證。JSON Schema 驗證的是已解析 JSON 的結構。如果某個欄位包含 JSON 字串,你需要先解析它再單獨驗證。某些驗證器提供自訂格式驗證器來處理此情況,但這不是標準的一部分。
相關資源
- JSON 格式化工具 — 格式化與美化你的 JSON Schema
- 如何驗證 JSON — 常見 JSON 驗證錯誤及修復方法
- JSON API 設計模式 — 使用 JSON 建構更好的 REST API