JSON Schema 到底能解决什么问题
结论:Schema 管的是结构和类型,管不了业务语义。它能把「字段缺失、类型错、枚举越界」挡在入口,但「金额为负、结束时间早于开始时间」这类规则,得靠代码校验。

结论:JSON Schema 负责结构、类型、取值范围与格式,跨字段依赖、业务不变量和外部状态必须放回代码;接口对外开放或多服务共享数据时引入,内部小服务字段少时手写判断更快。
能解决「这份数据长得对不对」,解决不了「这份数据说得通不通」。
它擅长的部分
结构完整性。 该有的字段有没有,多余的字段允不允许(required、additionalProperties)。
类型正确性。 port 是数字还是字符串,tags 是数组还是单个值。跨语言系统里这一条能省掉大量类型判断代码。
取值范围。 枚举(enum)、数值区间(minimum/maximum)、字符串长度(minLength/maxLength)、数组长度(minItems)。
格式约束。 日期、邮箱、URI、UUID 这些有公认写法的字段,用 format 声明,配合支持断言 format 的校验器使用。
嵌套结构。 对象里套对象、数组里套对象,每一层都能单独约束,错误信息能精确到路径。
契约文档化。 Schema 本身就是接口文档,改字段必须改 Schema,评审时一眼能看出影响范围。它还能反向生成 TypeScript 类型、Go 结构体、表单配置,属于「一处定义、多处消费」。
它管不了的部分
跨字段依赖。 「结束时间必须晚于开始时间」「A 字段为 true 时 B 才必填」,JSON Schema 的 if/then/else 能强行表达一部分,但写出来又长又难读,维护成本高于直接在代码里写三行判断。
业务不变量。 「库存不能为负」「同一订单号不能重复」,这依赖外部状态,Schema 只看单份数据,看不见数据库。
语义正确性。 price: -100 完全符合 {"type": "number"},但它是不是合法的价格,Schema 不知道。
性能与体积。 Schema 不限制请求体大小,也不管嵌套深度攻击,这些要在网关层做。
一个实用的分工
| 层次 | 谁负责 |
|---|---|
| 语法:是不是合法 JSON | 解析器 |
| 结构:字段、类型、范围、格式 | JSON Schema |
| 语义:跨字段、业务规则、外部状态 | 业务代码 |
| 安全:体积、深度、频率 | 网关 / 中间件 |
把四层混在一起做,最常见的后果是 Schema 膨胀到几百行、if/then 嵌套五六层,改一个字段要半天,最后大家绕开校验直接改代码。
什么时候值得引入
- 接口对外开放,调用方不可控
- 多个服务消费同一份数据,结构漂移会连锁出错
- 配置驱动,需要在校验阶段拦住手写错误
- 需要用 Schema 反向生成类型或表单
如果只是一个内部小服务、字段三五个、调用方就一个前端,写 if 判断比维护 Schema 更快——这时候引入 Schema 是负收益。
常见问题
如何判断一个项目该不该引入 JSON Schema?
看接口是否对外开放、是否有多个服务消费同一份数据、是否需要反向生成类型或表单。若是内部小服务、字段三五个、调用方只有一个前端,写 if 判断比维护 Schema 更快。
为什么跨字段规则不该硬写进 Schema?
「结束时间必须晚于开始时间」这类规则虽然能用 if/then/else 表达,但写出来又长又难读,维护成本高于直接在代码里写三行判断。
是否可以用 Schema 校验请求体大小和嵌套深度?
不能。Schema 只看数据结构,不限制体积与深度,这类安全约束要在网关或中间件层处理。
相关工具
- JSON Schema 从入门到工程化:从
type到$ref的完整写法 - 生成的 Schema 为何拒绝真实数据:自动生成后必然要手改的地方
- Schema 与 TypeScript 类型双向同步:类型是产物,不是源