数据校验:JSON Schema To Zod Schema — Numio
使用 json-schema-to-zod 根据 JSON Schema 生成 Zod 校验代码。minLength、minimum、pattern、default 等约束会变为链式调用的 Zod 方法,未列在 "required" 中的属性会加上 .optional()。
你从其他团队拿到 JSON Schema,想在 TypeScript 服务中做运行时校验,而不引入 JSON Schema 校验器。
适用场景
- 你从其他团队拿到 JSON Schema,想在 TypeScript 服务中做运行时校验,而不引入 JSON Schema 校验器。
- 你正把表单校验从 Ajv 等 JSON Schema 校验器迁移到 Zod,需要一份生成的代码作为起点。
使用方法
- 将 JSON Schema 粘贴到 JSON Schema 面板。
- 可选:打开设置修改 Root Schema Name(默认为 "schema"),它会成为导出的 const 名称。
- 将生成的代码(从 "zod" 导入 z)复制到项目中。转换在浏览器中进行。
JSON Schema
{
"type": "object",
"properties": {
"username": { "type": "string", "minLength": 3, "maxLength": 20 },
"age": { "type": "integer", "minimum": 18 },
"contact": {
"oneOf": [
{ "type": "string", "format": "email" },
{ "type": "string", "pattern": "^\\+[0-9]+$" }
]
},
"newsletter": { "type": "boolean", "default": false }
},
"required": ["username", "contact"]
}Zod schema
import { z } from "zod"
export const schema = z.object({
username: z.string().min(3).max(20),
age: z.number().int().gte(18).optional(),
contact: z.any().superRefine((x, ctx) => {
const schemas = [
z.string().email(),
z.string().regex(new RegExp("^\\+[0-9]+$")),
]
const errors = schemas.reduce(
(errors: z.ZodError[], schema) =>
((result) => ("error" in result ? [...errors, result.error] : errors))(
schema.safeParse(x),
),
[],
)
if (schemas.length - errors.length !== 1) {
ctx.addIssue({
path: ctx.path,
code: "invalid_union",
unionErrors: errors,
message: "Invalid input: Should pass single schema",
})
…功能与限制
oneOf 会转换为 z.any().superRefine(...),检查是否恰好有一个子 schema 通过,如示例所示。
$ref 不会被解析:引用其他 schema 的属性会变为 z.any()。
integer 会加上 .int(),format "email" 加上 .email(),format "date-time" 加上 .datetime()。
additionalProperties: false 会变为 .catchall(z.never()),而不是 .strict()。
FAQ
可为空的类型如何处理?
"type": ["string", "null"] 会变为 z.union([z.string(), z.null()]),若该属性不是必需的,还会加上 .optional()。
可以重命名导出的 schema 吗?
可以。在设置中指定 Root Schema Name,输出会变为 export const <name> = ...,而不是 export const schema。
支持 definitions 和 $ref 吗?
不支持。使用 $ref 的属性会变为 z.any(),请在转换前把被引用的 schema 内联进来。