JSON Schema 完全指南

通用 阅读约 18 分钟
JSONSchema验证API 设计OpenAPI

从基础到高级特性全面掌握 JSON Schema。学习验证关键字、allOf/anyOf/oneOf 组合、条件 Schema 以及面向 API 设计的实际示例。

什么是 JSON Schema?

JSON Schema 是一种声明性语言,用于验证 JSON 数据的结构。它就像一个合约,定义了你的 JSON 应该是什么样子。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "用户",
  "description": "系统中的用户",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "age": {
      "type": "integer",
      "minimum": 0,
      "maximum": 150
    },
    "email": {
      "type": "string",
      "format": "email"
    }
  },
  "required": ["name", "age"],
  "additionalProperties": false
}

基本类型

字符串

{
  "type": "string",
  "minLength": 1,
  "maxLength": 255,
  "pattern": "^[A-Za-z]+$"
}

格式emailuridatedate-timetimeipv4ipv6uuid

数字

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "multipleOf": 0.01
}

数组

{
  "type": "array",
  "items": { "type": "string" },
  "minItems": 1,
  "maxItems": 10,
  "uniqueItems": true
}

对象

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer" }
  },
  "required": ["name"],
  "additionalProperties": false
}

组合

allOf(与)

{
  "allOf": [
    { "type": "object", "properties": { "name": { "type": "string" } } },
    { "type": "object", "properties": { "age": { "type": "integer" } } }
  ]
}

anyOf(或)

{
  "anyOf": [
    { "type": "string" },
    { "type": "integer" }
  ]
}

oneOf(异或)

{
  "oneOf": [
    { "required": ["email"] },
    { "required": ["phone"] }
  ]
}

$ref(复用)

{
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      }
    }
  },
  "type": "object",
  "properties": {
    "home": { "$ref": "#/$defs/address" },
    "work": { "$ref": "#/$defs/address" }
  }
}

条件验证

{
  "type": "object",
  "properties": {
    "country": { "type": "string" },
    "postalCode": { "type": "string" }
  },
  "if": {
    "required": ["country"],
    "properties": { "country": { "const": "US" } }
  },
  "then": {
    "properties": {
      "postalCode": { "pattern": "^[0-9]{5}(-[0-9]{4})?$" }
    }
  },
  "else": {
    "properties": {
      "postalCode": { "minLength": 3 }
    }
  }
}

实际示例

API 请求验证

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 20,
      "pattern": "^[a-zA-Z0-9_]+$"
    },
    "password": {
      "type": "string",
      "minLength": 8,
      "pattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).*$"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "roles": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": ["admin", "user", "moderator"]
      },
      "uniqueItems": true
    }
  },
  "required": ["username", "password", "email"],
  "additionalProperties": false
}

配置文件

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "database": {
      "type": "object",
      "properties": {
        "host": { "type": "string" },
        "port": { "type": "integer", "default": 5432 },
        "name": { "type": "string" }
      },
      "required": ["host", "name"]
    },
    "logging": {
      "type": "object",
      "properties": {
        "level": {
          "type": "string",
          "enum": ["debug", "info", "warn", "error"]
        },
        "file": { "type": "string" }
      }
    }
  },
  "required": ["database"]
}

工具

验证库

语言
JavaScriptajvjoizod
Pythonjsonschemapydantic
Javaeverit-json-schema
Gogojsonschema
C#JsonSchema.Net

代码生成

# 从 JSON Schema 生成 TypeScript
npx json-schema-to-typescript schema.json > types.ts

# 从 JSON Schema 生成 Python
datamodel-codegen --input schema.json --output models.py

最佳实践

  1. 从简单开始 — 按需添加约束
  2. 使用 $ref — 不要重复自己
  3. 版本化 schema — 在 $id 中包含版本
  4. 充分测试 — 使用有效和无效测试用例
  5. 文档化格式 — 自定义格式需要自定义验证器

相关资源

各语言 JSON API 对比

语言 序列化 反序列化 美化输出 配置方式
Python json(内置) json.dumps(obj) json.loads(str) json.dumps(obj, indent=2) ensure_ascii, default, cls
JavaScript JSON(内置) JSON.stringify(obj) JSON.parse(str) JSON.stringify(obj, null, 2) replacer, space
Java Jackson / Gson mapper.writeValueAsString(obj) mapper.readValue(str, Class.class) mapper.writerWithDefaultPrettyPrinter() 注解、Module、Feature
Go encoding/json(内置) json.Marshal(obj) json.Unmarshal(data, &obj) json.MarshalIndent(obj, "", " ") struct tag
C# System.Text.Json(内置) JsonSerializer.Serialize(obj) JsonSerializer.Deserialize<T>(str) WriteIndented = true JsonSerializerOptions
TypeScript JSON(内置) JSON.stringify(obj) JSON.parse(str) JSON.stringify(obj, null, 2) replacer, space
Rust serde_json serde_json::to_string(&obj) serde_json::from_str::<T>(str) serde_json::to_string_pretty(&obj) serde attributes, custom (de)serializers

常见问题 (FAQ)

JSON 序列化时如何处理日期时间类型?

大多数语言的 JSON 库默认不支持日期时间类型。通常做法是序列化为 ISO 8601 格式字符串(如 "2026-07-15T10:30:00Z")或 Unix 时间戳,反序列化时再转换回日期时间对象。

如何忽略 JSON 序列化中的 null 值或空字段?

不同语言的实现方式不同:Python 可在自定义编码器中过滤 None 值;JavaScript 可使用 replacer 函数;Java Jackson 用 @JsonInclude 注解;Go 使用 omitempty struct tag;C# 设置 DefaultIgnoreCondition。

JSON 序列化时如何处理循环引用?

循环引用是 JSON 序列化的常见陷阱。标准 JSON 库通常会抛出异常或栈溢出。解决方案包括:使用 @JsonIdentityInfo 注解(Java Jackson)、实现自定义序列化器、将对象图转换为 DTO 后再序列化。

为什么我的私有字段没有被序列化?

JSON 序列化库通常只序列化公开(public)字段或带有 getter 的属性。Python 的 json 模块默认只序列化 dict 的公共键;Java Jackson 可通过 @JsonInclude 注解包含非公共成员。

JSON 序列化性能有哪些优化技巧?

1) 复用序列化器实例;2) 对于大型数据,使用流式 API;3) 使用编译时生成(C# Source Generator、Go easyjson);4) 避免过多嵌套层次;5) 使用数据库分页或分块传输大 JSON。

推荐工具

以下工具可以帮助你在 通用 开发中更高效地处理 JSON 数据:

相关文章