ToolHub
View All Posts

JSON Schema 验证指南:验证你的数据结构

每个从外部来源接收数据的应用程序都面临同一个根本问题:我能信任这些数据吗?无论是 API 请求体、配置文件、队列消息还是数据导入,不可信的数据在进入系统之前都必须经过验证。JSON Schema 提供了一种标准化的、与语言无关的方式来定义有效数据的样子,并验证传入数据是否符合该定义。本指南涵盖了从编写第一个 Schema 到复杂验证的高级模式的所有内容,并提供了可以立即应用的实用示例。

什么是 JSON Schema?

JSON Schema 是一个描述其他 JSON 文档结构和约束的 JSON 文档。它是一种允许你注解和验证 JSON 数据的词汇表,由互联网工程任务组(IETF)标准化。JSON Schema 定义了关于必须存在哪些字段、它们必须是什么类型、哪些值是可接受的以及对象和数组应该如何结构的规则。

把 JSON Schema 想象成你的数据契约。就像数据库 Schema 定义了表的列、类型和约束一样,JSON Schema 定义了 JSON 文档的属性、类型和约束。任何满足 Schema 中所有约束的 JSON 数据被称为有效实例,而违反任何约束的数据则是无效的。

JSON Schema 不是什么

JSON Schema 版本

JSON Schema 经历了多个草案的演进,每个草案都添加了功能并完善了词汇表。了解这些版本有助于你为项目选择合适的版本并避免兼容性问题。

版本$schema URI状态主要功能
Draft 2020-12https://json-schema.org/draft/2020-12/schema当前版本prefixItems, dynamicRef, 词汇表支持
Draft 2019-09https://json-schema.org/draft/2019-09/schema稳定版unevaluatedProperties, $recursiveRef
Draft 7http://json-schema.org/draft-07/schema#广泛支持if/then/else, contentEncoding
Draft 6http://json-schema.org/draft-06/schema#旧版propertyNames, contains
Draft 4http://json-schema.org/draft-04/schema#已弃用最初广泛采用的版本
建议:新项目使用 Draft 2020-12。它是最新稳定版本,功能最多,受主要验证库支持。如果需要与现有工具的最大兼容性,Draft 7 是安全的选择。避免使用 Draft 4 及更早版本。

编写你的第一个 Schema

让我们从一个简单的例子开始:一个包含姓名、邮箱和年龄的用户对象的 Schema。

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://example.com/schemas/user.json",
    "title": "User",
    "description": "A user account in the system",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "The user's full name"
        },
        "email": {
            "type": "string",
            "format": "email",
            "description": "The user's email address"
        },
        "age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 150,
            "description": "The user's age in years"
        }
    },
    "required": ["name", "email"],
    "additionalProperties": false
}

此 Schema 声明了一个有效用户必须是一个对象,其中 name 和 email 是必需的字符串属性。age 属性是可选的,但如果存在则必须是 0 到 150 之间的整数。additionalProperties: false 约束阻止了任何未在 Schema 中定义的属性,这可以捕获拼写错误和意外字段。

核心关键字参考

JSON Schema 提供了丰富的关键字词汇表来定义约束。以下按类别组织的最重要的关键字。

类型关键字

关键字描述示例
type预期数据类型"type": "string" 或 "type": ["string", "null"]
enum允许的值列表"enum": ["active", "inactive", "pending"]
const必须等于此精确值"const": "v2"

数字约束

关键字描述示例
minimum最小值(包含)"minimum": 0
exclusiveMinimum最小值(不包含)"exclusiveMinimum": 0
maximum最大值(包含)"maximum": 100
exclusiveMaximum最大值(不包含)"exclusiveMaximum": 100
multipleOf必须为此值的倍数"multipleOf": 0.01

字符串约束

关键字描述示例
minLength最小字符串长度"minLength": 1
maxLength最大字符串长度"maxLength": 255
pattern字符串必须匹配的正则表达式"pattern": "^[A-Z]{2}\\d{4}$"
format语义格式(email、uri、date-time 等)"format": "email"

对象约束

关键字描述示例
properties每个已知属性的 Schema"properties": {"name": {"type": "string"}}
required必需属性列表"required": ["name", "email"]
additionalProperties是否允许额外属性"additionalProperties": false
minProperties最小属性数量"minProperties": 1
maxProperties最大属性数量"maxProperties": 10
patternProperties匹配正则表达式的属性 Schema"patternProperties": {"^S_": {"type": "string"}}

数组约束

关键字描述示例
items所有数组项的 Schema"items": {"type": "string"}
prefixItems位置项的 Schema(Draft 2020-12)"prefixItems": [{"type": "string"}, {"type": "number"}]
minItems最小项数"minItems": 1
maxItems最大项数"maxItems": 100
uniqueItems所有项必须唯一"uniqueItems": true

常见 Schema 模式

现实世界中的 Schema 通常需要超越简单类型检查的模式。以下是最常用的模式。

使用 if/then/else 进行条件验证

使用条件逻辑根据属性值应用不同的约束。例如,支付对象根据支付方式需要不同的字段。

{
    "type": "object",
    "properties": {
        "method": { "enum": ["credit_card", "bank_transfer"] },
        "card_number": { "type": "string" },
        "routing_number": { "type": "string" }
    },
    "required": ["method"],
    "if": {
        "properties": { "method": { "const": "credit_card" } }
    },
    "then": {
        "required": ["card_number"]
    },
    "else": {
        "required": ["routing_number"]
    }
}

使用 allOf、anyOf、oneOf 进行组合

组合关键字允许你以强大的方式组合 Schema:

{
    "oneOf": [
        {
            "type": "object",
            "properties": {
                "type": { "const": "email" },
                "address": { "type": "string", "format": "email" }
            },
            "required": ["type", "address"]
        },
        {
            "type": "object",
            "properties": {
                "type": { "const": "phone" },
                "number": { "type": "string", "pattern": "^\\+?[1-9]\\d{1,14}$" }
            },
            "required": ["type", "number"]
        }
    ]
}

使用 $ref 复用 Schema

$ref 关键字允许你引用和复用 Schema,消除重复并保持 Schema 的可维护性。你可以引用同一文档内或外部文件中的 Schema。

{
    "$id": "https://example.com/schemas/order.json",
    "type": "object",
    "properties": {
        "customer": { "$ref": "#/$defs/address" },
        "shipping": { "$ref": "#/$defs/address" },
        "billing": { "$ref": "#/$defs/address" },
        "items": {
            "type": "array",
            "items": { "$ref": "#/$defs/lineItem" },
            "minItems": 1
        }
    },
    "required": ["customer", "items"],
    "$defs": {
        "address": {
            "type": "object",
            "properties": {
                "street": { "type": "string" },
                "city": { "type": "string" },
                "zip": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" },
                "country": { "type": "string", "minLength": 2, "maxLength": 2 }
            },
            "required": ["street", "city", "zip", "country"]
        },
        "lineItem": {
            "type": "object",
            "properties": {
                "product": { "type": "string" },
                "quantity": { "type": "integer", "minimum": 1 },
                "price": { "type": "number", "exclusiveMinimum": 0 }
            },
            "required": ["product", "quantity", "price"]
        }
    }
}

可空类型

在 JSON Schema Draft 2020-12 中,可空类型使用包含 "null" 的类型数组来表示:

{
    "type": ["string", "null"],
    "description": "An optional display name, or null if not set"
}

在较早的草案中,OpenAPI 规范使用了 nullable: true 关键字。对于标准 JSON Schema,请始终使用类型数组方法。

格式验证

format 关键字提供了超越结构检查的语义验证。它指定字符串必须符合一种众所周知的格式。常用支持的格式包括:

格式描述示例
email电子邮件地址user@example.com
uri有效的 URIhttps://example.com/path
uri-referenceURI 或相对引用/path/to/resource
date-timeISO 8601 日期时间2026-05-19T14:30:00Z
dateISO 8601 日期2026-05-19
timeISO 8601 时间14:30:00Z
ipv4IPv4 地址192.168.1.1
ipv6IPv6 地址::1
uuid通用唯一标识符550e8400-e29b-41d4-a716-446655440000
hostname互联网主机名www.example.com
重要提示:默认情况下,format 关键字是注解而非约束。验证器可能会忽略它,除非你明确启用格式验证。在 Ajv 中,传递 { strict: true } 或 { validateFormats: true } 来强制格式检查。始终验证你的验证器是否强制执行格式约束。

以编程方式验证 JSON 数据

Schema 验证在集成到应用程序代码中时最为有用。以下是使用不同语言中流行库的示例。

JavaScript 使用 Ajv

Ajv 是 JavaScript 中使用最广泛的 JSON Schema 验证器。它支持所有草案版本,并通过 Schema 的 JIT 编译提供出色的性能。

import Ajv from 'ajv';
import addFormats from 'ajv-formats';

const ajv = new Ajv();
addFormats(ajv);

const schema = {
    type: 'object',
    properties: {
        name: { type: 'string', minLength: 1 },
        email: { type: 'string', format: 'email' },
        age: { type: 'integer', minimum: 0 }
    },
    required: ['name', 'email'],
    additionalProperties: false
};

const validate = ajv.compile(schema);
const valid = validate({ name: 'Alice', email: 'alice@example.com', age: 30 });

if (!valid) {
    console.log(validate.errors);
    // [{ keyword: 'required', params: { missingProperty: 'email' }, ... }]
}

Python 使用 jsonschema

from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "minLength": 1},
        "email": {"type": "string", "format": "email"},
        "age": {"type": "integer", "minimum": 0}
    },
    "required": ["name", "email"],
    "additionalProperties": False
}

try:
    validate(instance={"name": "Alice", "email": "alice@example.com"}, schema=schema)
except ValidationError as e:
    print(f"Validation failed: {e.message}")

使用 JSON Schema 进行 API 数据验证

JSON Schema 最有价值的应用之一是验证 API 请求和响应数据。这确保了你的 API 接收格式良好的输入并以预期格式返回数据,能够及早捕获错误并向客户端提供清晰的错误消息。

Express.js 中间件

import Ajv from 'ajv';

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

function validateBody(schema) {
    const validate = ajv.compile(schema);
    return (req, res, next) => {
        if (!validate(req.body)) {
            return res.status(400).json({
                error: 'Validation failed',
                details: validate.errors
            });
        }
        next();
    };
}

app.post('/api/users',
    validateBody({
        type: 'object',
        properties: {
            name: { type: 'string', minLength: 1, maxLength: 100 },
            email: { type: 'string', format: 'email' },
            role: { enum: ['admin', 'editor', 'viewer'] }
        },
        required: ['name', 'email'],
        additionalProperties: false
    }),
    (req, res) => {
        // req.body is guaranteed valid here
        createUser(req.body);
    }
);

OpenAPI 与 JSON Schema

OpenAPI(前身为 Swagger)使用 JSON Schema 的一个子集来定义 API 请求和响应 Schema。如果你已经在使用 OpenAPI,可以从 API 规范中提取 Schema 并将其用于运行时验证。像 openapi-schema-validator 和 express-openapi-validator 这样的工具可以自动化这个过程,确保你的 API 文档和验证逻辑始终保持同步。

最佳实践

需要根据 Schema 验证 JSON 数据?试试我们免费的在线 JSON Schema 验证器。粘贴你的 Schema 和数据,即可获得带有详细错误信息的即时验证结果。

JSON Schema 验证器JSON 格式化工具

常见问题

什么是 JSON Schema?

JSON Schema 是一个描述其他 JSON 文档结构和约束的 JSON 文档。它让你可以定义必需字段、预期数据类型、值范围、字符串模式和嵌套对象结构。你可以用它来验证传入数据、生成文档和自动创建表单界面。

我应该使用哪个版本的 JSON Schema?

新项目请使用 JSON Schema Draft 2020-12。这是最新的稳定版本,Ajv 等主要验证库都支持它。如果需要与旧工具兼容,Draft 7 也被广泛支持。避免使用 Draft 4 及更早版本,因为它们使用过时的关键字且缺乏现代功能。

JSON Schema 与 TypeScript 接口有什么区别?

TypeScript 接口仅在 TypeScript 代码中提供编译时类型检查。JSON Schema 提供跨编程语言的运行时验证,可以验证来自任何来源(API 请求、文件、数据库)的数据。使用 TypeScript 获得开发时的安全性,使用 JSON Schema 在系统边界进行运行时数据验证。

JSON Schema 可以验证 API 请求体吗?

是的,JSON Schema 被广泛用于 API 请求和响应验证。Express(配合 express-json-validator)、FastAPI 和 Spring Boot 等框架原生支持或通过中间件支持 JSON Schema 验证。根据 Schema 验证请求体可确保传入数据在应用程序处理之前具有正确的结构。

最重要的 JSON Schema 关键字有哪些?

最关键的关键字是:type(数据类型)、properties(对象字段)、required(必需字段)、items(数组元素 Schema)、minimum/maximum(数值边界)、minLength/maxLength(字符串边界)、pattern(字符串正则表达式)、enum(允许的值)和 $ref(复用 Schema 的引用)。这些关键字覆盖了绝大多数验证需求。