Zum Inhalt springen

JSON Schema in Zod umwandeln — Numio

Erzeugt mit json-schema-to-zod Zod-Validierungscode aus einem JSON Schema. Einschränkungen wie minLength, minimum, pattern und default werden zu verketteten Zod-Methoden, und Properties, die nicht in "required" stehen, erhalten .optional().

Du bekommst ein JSON Schema von einem anderen Team und willst Laufzeitvalidierung in einem TypeScript-Service ohne JSON-Schema-Validator.

JSON Schema

Zod Schema

Wann sie hilft

  • Du bekommst ein JSON Schema von einem anderen Team und willst Laufzeitvalidierung in einem TypeScript-Service ohne JSON-Schema-Validator.
  • Du migrierst Formularvalidierung von einem JSON-Schema-Validator wie Ajv zu Zod und willst generierten Code als Ausgangspunkt.

Anwendung

  1. Füge ein JSON Schema in das Panel JSON Schema ein.
  2. Öffne optional die Einstellungen und ändere Root Schema Name (Standard "schema"); er wird zum Namen der exportierten const.
  3. Kopiere den generierten Code, der z aus "zod" importiert, in dein Projekt. Die Konvertierung läuft im Browser.

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",
      })
…

Details und Einschränkungen

oneOf wird zu z.any().superRefine(...) konvertiert, das prüft, dass genau ein Teilschema passt, wie das Beispiel zeigt.

$ref wird nicht aufgelöst: Eine referenzierte Property wird zu z.any().

integer ergänzt .int(), format "email" ergänzt .email() und format "date-time" ergänzt .datetime().

additionalProperties: false wird zu .catchall(z.never()) statt zu .strict().

FAQ

Wie werden nullable Typen behandelt?

"type": ["string", "null"] wird zu z.union([z.string(), z.null()]), mit .optional(), wenn die Property nicht required ist.

Kann ich das exportierte Schema umbenennen?

Ja. Setze Root Schema Name in den Einstellungen; die Ausgabe lautet dann export const <name> = ... statt export const schema.

Werden definitions und $ref unterstützt?

Nein. Eine Property mit $ref wird zu z.any(); füge das referenzierte Schema daher vor der Konvertierung inline ein.

Spezifikationen und Referenzen