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