跳到主要内容

从 JSON 示例到 JSON Schema:怎么生成一份能直接用的校验规则

把一段真实 JSON 粘进来,就能得到带类型的 JSON Schema。本文讲清 type、required、properties 怎么从样本推断出来,嵌套对象如何映射,以及拿这份 schema 做数据校验和接口契约的具体方法。

发布于 作者 李雷
#json schema #json #数据校验 #接口契约 #开发工具

从 JSON 示例生成 JSON Schema:让校验规则自己长出来

写接口的人都遇到过这种场景:手里有一段能跑的 JSON 响应,文档里却还空着一份 schema。手敲花括号、对照字段补类型、再决定哪些必填,十分钟就这么没了。其实这份工作完全可以让机器读着数据自己生成。下面讲清 JSON Schema 到底描述什么、怎么从一个样本把 type、required、properties 推断出来,以及拿到 schema 之后能做哪些事。

JSON Schema 到底在描述什么

JSON Schema 是一套用来描述 JSON 数据形状的词汇:数据里有哪些键、每个键是什么类型、哪些键必须出现。它不是另一种数据格式,而是一份"合同",规定了一段 JSON 长什么样才算合法。

它能落到三种真实用途上。第一是数据校验,把 schema 接到 ajv 这类校验库或 CI 检查里,字段类型不对、必填项缺失就直接报错。第二是接口契约,前后端、服务和服务之间约定好请求体和响应体的结构,谁改了字段都能被发现。第三是文档,OpenAPI 的 components/schemas 直接吃 JSON Schema,编辑器也能据此做自动补全。

type、required、properties 是怎么推断出来的

生成器拿到样本后,先 JSON.parse,再递归遍历整个值,核心就是三件事。

type 是逐个值定的。字符串推成 string,布尔值推成 boolean,对象推成 object,数组推成 array。这里有个容易忽略的点:整数和小数不一样。样本值 10 会推成 integer,而不是 number,所以 10.5 反而过不了这份 schema。字段可能含小数的话,样本里要真出现一个小数,或者事后自己把类型放宽成 number。

properties 是对象的字段表。每个对象都会生成一份 properties,把它每个键对应的子 schema 列进去。

required 决定哪些键必填。默认情况下,对象里出现过的每个键都会进 required 数组,因为从单份样本能做的最稳妥假设,就是看到的键都是必填的。这也是单样本的天然局限:它只认得这份样本里有的键。要是别的记录带了样本里缺的可选字段,生成的 required 就会过严。应对办法是喂一个有代表性的数组,或者事后把不该必填的键从 required 里删掉。工具本身也提供「加 required」开关,关掉就一个 required 数组都不输出,所有字段变可选。

一个真实的输入输出例子

假设接口返回这样一段 JSON:

{ "id": 1, "name": "Lei", "active": true, "tags": ["dev", "ops"] }

粘进去生成,得到的 schema 是这样:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "name": { "type": "string" },
    "active": { "type": "boolean" },
    "tags": { "type": "array", "items": { "type": "string" } }
  },
  "required": ["id", "name", "active", "tags"]
}

可以看到:id 因为是整数被标成 integer,name 是 string,active 是 boolean。tags 是一个字符串数组,所以 type 为 array,items 收敛成一份 { "type": "string" }。四个键全部进了 required。把这段直接贴进 OpenAPI 的 components/schemas,或者交给 ajv,就立刻能跑。

嵌套和混合类型怎么办

样本结构会一比一映射:三层嵌套的对象,生成的就是三层嵌套的 schema。每往下一层,生成器就再开一份 properties,直到叶子节点收到具体类型。所以不用担心深层结构被压扁,数据长成什么样,schema 就长成什么样。

数组里类型混在一起时单一 items 就不够用了。比如 [1, "two", true],工具会把 items 写成 anyOf,列出每种不同的元素 schema:{ "anyOf": [{ "type": "integer" }, { "type": "string" }, { "type": "boolean" }] },这样每个出现过的元素都合法。同质数组比如 [1, 2, 3] 则合并成一份 items,空数组就把 items 留空开放。

我自己的用法

我接手过一个老服务,它读一份有三十来个键、却零校验的 settings.json,一个布尔开关打错字就在凌晨崩在生产环境。我做的就是把一份合法配置丢进生成器,拿到 schema,接进 CI 检查。从那以后,任何一个字段类型写错都会让构建直接红掉,而不是等到半夜出事。整个过程没手敲过一个花括号,类型也和数据对得死死的,因为它是从数据里读出来的,不是我猜的。

需要注意一点:这个工具推断的是结构类型(string、integer、object、array),不会去认 date-time、email、uuid 这类语义格式。时间戳字符串出来就是 type string,需要格式约束的地方,自己补上 format 关键字。

小结

从一个 JSON 样本生成 schema,本质是让机器替你读数据、定类型、列必填。记住三个要点就够用:integer 和 number 要分清,单样本的 required 偏严要手动放宽,语义格式得自己补。生成好之后,可以顺手用 JSON Schema 生成器 反复迭代;如果还想把同一段数据在不同格式间倒腾,JSON 格式化工具 能先帮你把样本整理干净再来生成。


Made by Toolora · Updated 2026-06-13