跳到主要内容
AZ Tools

JSON Schema 校验器

左边粘贴 schema,右边粘贴文档,就能知道文档是否通过;没通过时,逐条给出错在哪里、为什么。每条错误一行:文档中的 JSON 指针、失败的关键字、该关键字在 schema 中的位置、当时的取值,以及只有指针给不出的一项——它落在你粘贴文本的第几行。行的顺序和读文件的顺序一致,第一行就是往下滚动时最先遇到的问题。 真正让这个工具好用的是 anyOf 和 oneOf 的呈现方式。多数校验器把分支错误摊平成一长串,真正有用的那句话反而被淹没。这里失败仍然是一行,下面按分支列出各自的要求和各自的错误,并把问题最少的分支标为“最接近”,那通常就是你本来想写的分支。oneOf 同时命中两个分支时,也会作为独立的失败报告,并指出是哪几个分支。 草案版本会改变结论,所以工具会显示用了哪一版、以及是来自 $schema 还是来自选择框。在草案 4 中 1.0 不是整数,exclusiveMinimum 是修饰 minimum 的布尔值;从草案 6 起 1.0 是整数,exclusiveMinimum 直接是边界值。草案 7 及更早,写在 $ref 旁边的关键字一律被忽略。还有一些各版本一致却容易误解的规则:required 只看是否存在,值为 null 也算存在;minLength 数的是码点,表情符号算 1,用组合字符写的重音算 2;二进制浮点下 0.3 不是 0.1 的倍数;只有键顺序不同的两个对象是同一个值,而顺序不同的两个数组不是。 schema 本身也可能是坏的,那是另一种答案:类型名拼错、required 不是数组、pattern 无法编译、$ref 指向不存在的位置,都会作为 schema 缺陷连同位置一起报告,而不是变成文档的通过或不通过。 它给不了的答案同样写清楚:不联网,所以指向 URL 的 $ref 无法解析,需要先并入 $defs;unevaluatedProperties、unevaluatedItems 和 $dynamicRef 只提示不求值;超过 2^53 的整数按双精度读取,服务端校验器不会这样;正则用的是规范要求的浏览器引擎,与 Python 或 Go 在边角处不同。全部处理都在本页完成,schema 和文档都不会离开你的设备。

format 默认只是注解。打开后才会真正报错。

schema 中若写了 $schema,就按它选草案;只有没写时才用这里的设置。

结果

未通过

错误

7

草案版本

2020-12

文档

12 行,169 字节

7 个错误2020-12 · 由 $schema 指定
整个文档行 1additionalProperties

schema 不允许其他属性,但出现了:"debug"

debug (行 11)

值: {"name":"","version":"2.1","server":{"host":"0.0.0.0","port":99999,"tls":"yes"},"workers":…

schema: /additionalProperties

/name行 2minLength

字符串有 0 个码点,最少需要 1 个

值: ""

schema: /properties/name/minLength

/version行 3pattern

"2.1" 与模式 ^\d+\.\d+\.\d+$ 不匹配

值: "2.1"

schema: /properties/version/pattern

/server/port行 6maximum

99999 大于最大值 65535

值: 99999

schema: /properties/server/properties/port/maximum

/server/tls行 7type

"yes" 是 string,而 schema 要求 boolean

值: "yes"

schema: /properties/server/properties/tls/type

/workers行 9anyOf

anyOf 的 2 个分支都不接受这个值

值: 0

schema: /properties/workers/anyOf

逐个分支

分支 1 type: integer 1 个问题最接近

  • /workers — 0 小于最小值 1

分支 2 const: "auto" 1 个问题

  • /workers — 0 不等于常量 "auto"
/tags行 10uniqueItems

索引 0 和索引 1 的元素是同一个值:"a"

值: ["a","a"]

schema: /properties/tags/uniqueItems

全部在本页面内完成,schema 和文档都不会上传。

使用方法

  1. 第一个框里粘贴 schema,第二个框里粘贴要校验的文档。两个框的内容都会保存,关掉页面再回来还在。
  2. 看概览卡片:是否通过、错误数量、使用的草案版本以及文档大小。草案那一行还会说明它来自 $schema 还是选择框。
  3. 自上而下看错误行。每行给出 JSON 指针、文档中的行号、失败的关键字、当时的取值和 schema 内的位置,便于判断该改哪一边。
  4. 展开 anyOf 或 oneOf 的那一行看分支列表。标为“最接近”的分支失败得最少,通常就是你想要的那个。
  5. 希望 format 真正报错时打开“校验 format”。规范把 format 定义为注解,所以默认是关闭的。

常见问题

为什么本该失败的文档却通过了?
多半是因为 schema 说的比看起来少。JSON Schema 会忽略不认识的关键字,所以把 required 写成 require、把 minLength 写成 minlength,或者在 draft-07 的 schema 里用 2020-12 的关键字,都不是错误,而是什么都不做的注解。对象在没有 additionalProperties 或 unevaluatedProperties 时会接受额外属性,数组在没有 items 或 prefixItems 时什么都收,format 在打开校验前也只是注解。另外请看卡片上的草案版本:某个关键字可能只存在于部分草案,本工具也会忽略所选草案里没有的关键字。
1.0 算整数吗?
草案 6 及以后算:规范按值定义 integer,所以 1.0 和 1.0e2 是整数,1.5 不是。草案 4 不算:写了小数点的数是浮点数,会在 "type": "integer" 上失败。本工具在解析时记住了每个数字的书写形式,才能区分 1 和 1.0;只用 JSON.parse 的话两者完全相同。如果你在用旧库配合 draft-04 的 schema,这个差异会造成真实的线上意外,在这里切换草案选择就能复现。
为什么 0.3 不是 0.1 的倍数?
因为这两个数在二进制浮点里都不精确。0.3 除以 0.1 得到的是 2.9999999999999996 而不是 3,而参考实现检查的正是这个商,于是文档被拒绝。把值改成 3、multipleOf 写成 1 就能通过。这不是本工具的怪癖:python-jsonschema、ajv 等在小数 multipleOf 上的行为都一样。所以想表达“两位小数”,用 pattern 或者用以分为单位的整数更稳妥。
错误里的 JSON 指针怎么读?
指针是从文档根开始、以斜杠分隔的路径:/server/port 是 server 对象的 port,/tags/2 是 tags 的第三个元素,因为下标从 0 开始。空指针表示整个文档,这也是 required、additionalProperties 和 uniqueItems 的错误指向容器对象或数组而不是成员的原因——缺失的属性本来就没有自己的位置。属性名中的斜杠写成 ~1,波浪号写成 ~0。指针旁边的行号,是本工具在你粘贴的原文中解析这条路径得到的。
为什么别的校验器在 anyOf 上会输出一大堆错误?
因为 anyOf 失败意味着所有分支都失败了,那些错误在技术上都成立。不做整理的校验器会把它们并排打印,于是“字符串和对象的联合”会变成一份清单:“不是 string 类型”旁边紧跟着一个你根本没打算写的对象缺少必需属性。按分支分组,就把 schema 原有的结构还了回来;挑失败最少的那个分支,绝大多数时候就能找到你想要的那支。这是启发式而非证明:如果两个分支各错一处,工具只会标出前一个,schema 本身也说不出你要的是哪一个。
它会跟随指向其他文件或 URL 的 $ref 吗?
不会,这是刻意的:本工具不联网,所以指向 https://example.com/user.json 或相邻文件 common.json#/$defs/id 的引用无法解析,并且不会被悄悄忽略,而是作为 schema 缺陷报告出来。粘贴文本内部的引用完全可用:#/$defs/name、单独的 #、回到根的递归引用、$anchor,以及被其他引用按名字指向的 $id。要校验拆成多个文件的 schema,请先合并:把被引用的定义放进 $defs 并改写引用路径,这也是多数工具在发布 schema 前会做的事。

相关工具