JSON Schema를 Zod 스키마로 변환 — Numio
json-schema-to-zod로 JSON Schema에서 Zod 검증 코드를 생성합니다. minLength, minimum, pattern, default 같은 제약은 체이닝된 Zod 메서드가 되고, "required"에 없는 속성에는 .optional()이 붙습니다.
다른 팀에서 JSON Schema를 받았고, JSON Schema 검증기 없이 TypeScript 서비스에서 런타임 검증을 하고 싶을 때.
이럴 때 사용하세요
- 다른 팀에서 JSON Schema를 받았고, JSON Schema 검증기 없이 TypeScript 서비스에서 런타임 검증을 하고 싶을 때.
- 폼 검증을 Ajv 같은 JSON Schema 검증기에서 Zod로 옮기는 중이라 출발점이 될 생성 코드가 필요할 때.
사용 방법
- JSON Schema 패널에 JSON Schema를 붙여 넣습니다.
- 필요하면 설정을 열어 Root Schema Name(기본값 "schema")을 바꿉니다. 이 값이 export되는 const 이름이 됩니다.
- "zod"에서 z를 import하는 생성 코드를 프로젝트에 복사합니다. 변환은 브라우저에서 실행됩니다.
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 스키마
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(...)으로 변환되어, 하위 스키마 중 정확히 하나만 통과하는지 검사합니다.
$ref는 해석되지 않으며, 참조하는 속성은 z.any()가 됩니다.
integer에는 .int(), format "email"에는 .email(), format "date-time"에는 .datetime()이 붙습니다.
additionalProperties: false는 .strict()가 아니라 .catchall(z.never())가 됩니다.
FAQ
nullable 타입은 어떻게 처리되나요?
"type": ["string", "null"]은 z.union([z.string(), z.null()])이 되고, 필수가 아닌 속성이면 .optional()이 추가됩니다.
export되는 스키마 이름을 바꿀 수 있나요?
네. 설정에서 Root Schema Name을 지정하면 출력이 export const schema 대신 export const <name> = ...이 됩니다.
definitions와 $ref를 지원하나요?
아니요. $ref를 쓰는 속성은 z.any()가 되므로, 변환 전에 참조된 스키마를 인라인으로 넣으세요.