← 返回博客

理解 JSON Schema:轻松验证

掌握 JSON Schema 进行数据验证。学习模式语法、验证技术以及在不同编程语言中的实现。

Big JSON Team14 分钟阅读advanced
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

14 分钟阅读

# 理解 JSON Schema:轻松验证

JSON Schema 是用于验证和描述 JSON 文档的词汇表。它定义了 JSON 数据的结构、约束和验证规则,确保数据质量和一致性。

什么是 JSON Schema?

JSON Schema 是一个强大的工具,用于:

  • 验证数据结构:确保 JSON 符合期望的格式
  • 文档化 API:清晰描述数据要求
  • 生成代码:自动创建类型定义
  • 测试:验证测试数据
  • 配置验证:检查配置文件

基本 Schema 示例

{

"$schema": "https://json-schema.org/draft/2020-12/schema",

"$id": "https://example.com/user.schema.json",

"title": "用户",

"type": "object",

"properties": {

"name": {

"type": "string",

"description": "用户姓名"

},

"age": {

"type": "integer",

"minimum": 0,

"maximum": 150,

"description": "用户年龄"

},

"email": {

"type": "string",

"format": "email",

"description": "电子邮件地址"

}

},

"required": ["name", "email"]

}

验证此数据:
{

"name": "张三",

"age": 30,

"email": "zhangsan@example.com"

}

✅ 有效

{

"name": "李四",

"email": "invalid-email"

}

❌ 无效(电子邮件格式错误)

Schema 关键字

类型关键字

type

定义值的数据类型:

{

"type": "string" // 字符串

}

{

"type": "number" // 数字

}

{

"type": "integer" // 整数

}

{

"type": "boolean" // 布尔值

}

{

"type": "object" // 对象

}

{

"type": "array" // 数组

}

{

"type": "null" // 空值

}

多类型

{

"type": ["string", "null"]

}

字符串验证

{

"type": "string",

"minLength": 3,

"maxLength": 50,

"pattern": "^[A-Za-z]+$"

}

格式:
{

"type": "string",

"format": "email" // 电子邮件

}

{

"type": "string",

"format": "uri" // URI

}

{

"type": "string",

"format": "date" // 日期 (YYYY-MM-DD)

}

{

"type": "string",

"format": "time" // 时间

}

{

"type": "string",

"format": "date-time" // 日期时间

}

{

"type": "string",

"format": "ipv4" // IPv4 地址

}

{

"type": "string",

"format": "ipv6" // IPv6 地址

}

数字验证

{

"type": "number",

"minimum": 0,

"maximum": 100,

"exclusiveMinimum": 0,

"exclusiveMaximum": 100,

"multipleOf": 5

}

示例:
{

"type": "integer",

"minimum": 18,

"maximum": 120,

"description": "年龄必须在 18 到 120 之间"

}

对象验证

{

"type": "object",

"properties": {

"name": {

"type": "string"

},

"age": {

"type": "integer"

}

},

"required": ["name"],

"additionalProperties": false,

"minProperties": 1,

"maxProperties": 10

}

数组验证

{

"type": "array",

"items": {

"type": "string"

},

"minItems": 1,

"maxItems": 10,

"uniqueItems": true

}

不同项类型:
{

"type": "array",

"items": [

{"type": "string"},

{"type": "number"},

{"type": "boolean"}

]

}

实际示例

用户注册 Schema

{

"$schema": "https://json-schema.org/draft/2020-12/schema",

"title": "用户注册",

"type": "object",

"properties": {

"username": {

"type": "string",

"minLength": 3,

"maxLength": 20,

"pattern": "^[a-zA-Z0-9_]+$",

"description": "用户名(仅字母数字和下划线)"

},

"email": {

"type": "string",

"format": "email",

"description": "有效的电子邮件地址"

},

"password": {

"type": "string",

"minLength": 8,

"description": "至少 8 个字符的密码"

},

"age": {

"type": "integer",

"minimum": 13,

"description": "必须至少 13 岁"

},

"terms": {

"type": "boolean",

"const": true,

"description": "必须接受条款"

}

},

"required": ["username", "email", "password", "terms"]

}

产品 Schema

{

"title": "产品",

"type": "object",

"properties": {

"id": {

"type": "string",

"pattern": "^PROD-[0-9]+$"

},

"name": {

"type": "string",

"minLength": 1

},

"price": {

"type": "number",

"minimum": 0,

"multipleOf": 0.01

},

"inStock": {

"type": "boolean"

},

"tags": {

"type": "array",

"items": {

"type": "string"

},

"uniqueItems": true

},

"specifications": {

"type": "object",

"additionalProperties": {

"type": "string"

}

}

},

"required": ["id", "name", "price"]

}

JavaScript 中的验证

使用 Ajv

安装:
npm install ajv
基本用法:
import Ajv from 'ajv';

import addFormats from 'ajv-formats';

const ajv = new Ajv();

addFormats(ajv);

const schema = {

type: 'object',

properties: {

name: { type: 'string', minLength: 2 },

email: { type: 'string', format: 'email' },

age: { type: 'integer', minimum: 0 }

},

required: ['name', 'email']

};

const validate = ajv.compile(schema);

// 测试数据

const data1 = {

name: "张三",

email: "zhangsan@example.com",

age: 30

};

if (validate(data1)) {

console.log('数据有效!');

} else {

console.log('验证失败:', validate.errors);

}

// 无效数据

const data2 = {

name: "李", // 太短

email: "invalid-email" // 无效格式

};

if (!validate(data2)) {

console.log('错误:', validate.errors);

// 错误: [

// {

// instancePath: '/name',

// message: 'must NOT have fewer than 2 characters'

// },

// {

// instancePath: '/email',

// message: 'must match format "email"'

// }

// ]

}

自定义错误消息

import Ajv from 'ajv';

import ajvErrors from 'ajv-errors';

const ajv = new Ajv({ allErrors: true });

ajvErrors(ajv);

const schema = {

type: 'object',

properties: {

age: {

type: 'integer',

minimum: 18,

errorMessage: '年龄必须至少为 18 岁'

}

},

required: ['age'],

errorMessage: {

required: '缺少必需字段'

}

};

const validate = ajv.compile(schema);

Python 中的验证

使用 jsonschema

安装:
pip install jsonschema
基本用法:
from jsonschema import validate, ValidationError

import json

schema = {

"type": "object",

"properties": {

"name": {

"type": "string",

"minLength": 2

},

"email": {

"type": "string",

"format": "email"

},

"age": {

"type": "integer",

"minimum": 0

}

},

"required": ["name", "email"]

}

# 有效数据

data = {

"name": "张三",

"email": "zhangsan@example.com",

"age": 30

}

try:

validate(instance=data, schema=schema)

print("数据有效!")

except ValidationError as e:

print(f"验证失败:{e.message}")

print(f"路径:{list(e.path)}")

使用 Pydantic

from pydantic import BaseModel, EmailStr, Field, validator

from typing import Optional

class User(BaseModel):

name: str = Field(..., min_length=2, max_length=50)

email: EmailStr

age: int = Field(..., ge=0, le=150)

phone: Optional[str] = None

@validator('name')

def name_must_not_contain_numbers(cls, v):

if any(char.isdigit() for char in v):

raise ValueError('姓名不能包含数字')

return v

# 使用

try:

user = User(

name="张三",

email="zhangsan@example.com",

age=30

)

print(f"用户创建成功:{user.name}")

except ValueError as e:

print(f"验证错误:{e}")

高级功能

$ref - Schema 引用

重用 schema 定义:

{

"$defs": {

"address": {

"type": "object",

"properties": {

"street": {"type": "string"},

"city": {"type": "string"},

"zipCode": {"type": "string", "pattern": "^[0-9]{6}$"}

},

"required": ["street", "city"]

}

},

"type": "object",

"properties": {

"homeAddress": {

"$ref": "#/$defs/address"

},

"workAddress": {

"$ref": "#/$defs/address"

}

}

}

allOf - 所有条件

{

"allOf": [

{"type": "object", "properties": {"name": {"type": "string"}}},

{"properties": {"age": {"type": "integer"}}}

]

}

anyOf - 任一条件

{

"anyOf": [

{"type": "string"},

{"type": "number"}

]

}

oneOf - 恰好一个条件

{

"oneOf": [

{"properties": {"type": {"const": "person"}}, "required": ["name"]},

{"properties": {"type": {"const": "company"}}, "required": ["companyName"]}

]

}

if/then/else - 条件验证

{

"type": "object",

"properties": {

"country": {"type": "string"}

},

"if": {

"properties": {"country": {"const": "中国"}}

},

"then": {

"properties": {

"postalCode": {"pattern": "^[0-9]{6}$"}

}

},

"else": {

"properties": {

"postalCode": {"type": "string"}

}

}

}

Schema 生成

从 JSON 生成

import json

from genson import SchemaBuilder

# 样本数据

data = [

{"name": "张三", "age": 30, "email": "zhangsan@example.com"},

{"name": "李四", "age": 25, "email": "lisi@example.com"}

]

# 生成 schema

builder = SchemaBuilder()

for item in data:

builder.add_object(item)

schema = builder.to_schema()

print(json.dumps(schema, indent=2, ensure_ascii=False))

从 TypeScript 接口

import { compile } from 'json-schema-to-typescript';

const schema = {

type: 'object',

properties: {

name: { type: 'string' },

age: { type: 'integer' }

}

};

compile(schema, 'User').then(ts => console.log(ts));

// 输出:

// export interface User {

// name?: string;

// age?: number;

// }

最佳实践

1. 使用描述性标题和描述

{

"title": "用户资料",

"description": "用于用户配置文件验证的完整 schema",

"properties": {

"email": {

"type": "string",

"format": "email",

"description": "用户的主要电子邮件地址"

}

}

}

2. 提供示例

{

"type": "object",

"properties": {

"status": {

"type": "string",

"enum": ["active", "inactive", "pending"],

"examples": ["active"]

}

}

}

3. 使用 $id 和 $schema

{

"$schema": "https://json-schema.org/draft/2020-12/schema",

"$id": "https://example.com/schemas/user.json"

}

4. 重用定义

{

"$defs": {

"positiveInteger": {

"type": "integer",

"minimum": 1

}

},

"properties": {

"age": { "$ref": "#/$defs/positiveInteger" },

"count": { "$ref": "#/$defs/positiveInteger" }

}

}

5. 验证敏感操作

// API 端点

app.post('/api/users', async (req, res) => {

const valid = validate(req.body);

if (!valid) {

return res.status(400).json({

error: '验证失败',

details: validate.errors

});

}

// 处理有效数据

const user = await createUser(req.body);

res.status(201).json(user);

});

工具和资源

在线验证器

  • JSON Schema Validator
  • JSONLint (with schema support)

JavaScript:
  • Ajv(最快)
  • Joi
  • Yup

Python:
  • jsonschema
  • Pydantic
  • marshmallow

其他语言:
  • Java: json-schema-validator
  • Go: gojsonschema
  • Ruby: json-schema

IDE 支持

  • VS Code:内置 JSON Schema 支持
  • IntelliJ:JSON Schema 插件
  • Sublime Text:LSP-json

结论

JSON Schema 是确保数据质量和一致性的强大工具。通过掌握 schema 定义和验证,您可以:

  • ✅ 防止无效数据进入系统
  • ✅ 清晰记录 API 合同
  • ✅ 自动生成类型定义
  • ✅ 提高代码质量和可维护性
  • ✅ 减少运行时错误

关键要点

  • 始终为 API 端点定义 schema
  • 使用 $ref 重用定义
  • 提供清晰的错误消息
  • 利用格式验证
  • 在开发和生产中进行验证
  • 开始在您的项目中使用 JSON Schema,享受类型安全和数据验证的好处!

    Share:

    相关文章

    Read in English