Skip to content
Mock and Match

How to convert JSON to Zod and validate API data

Generate Zod schemas from a JSON, validate API responses at runtime, and refine the schema with email, optional and nullable values.

Published on

Types don't validate anything at runtime

TypeScript interfaces disappear once the code is compiled. If an API starts returning a field in a different shape, or stops sending a field, your application only finds out when it breaks. Zod fixes that: you describe the expected shape in a schema, and it checks the real data as it arrives.

Writing schemas by hand for large responses is tedious. Converting a sample JSON into a Zod schema gives you the structure ready to refine.

Step by step

  1. Open Transform and choose JSON → Zod.
  2. Paste a JSON representative of the response you want to validate.
  3. Adjust the Root name (here, User) and click Transform.
  4. Install the library with npm install zod, import z, and paste in the generated schemas.

Example

The tool's real input and output:

Input (JSON)
{
  "id": 1,
  "name": "Ana Souza",
  "email": "ana@example.com",
  "active": true,
  "tags": ["admin", "beta"],
  "address": { "city": "São Paulo", "zip": "01310-100" }
}
Output (Zod)
const addressSchema = z.object({
  city: z.string(),
  zip: z.string(),
});

const userSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string(),
  active: z.boolean(),
  tags: z.array(z.string()),
  address: addressSchema,
});

Nested objects become separate schemas (addressSchema) that the main schema reuses, which keeps the code organized and easy to reuse.

Validating the API response

TypeScript: validating the response
import { z } from "zod";

// ... schemas generated by the tool ...

// The TypeScript type comes straight from the schema, no interface to write by hand.
type User = z.infer<typeof userSchema>;

const response = await fetch("/api/users/1");
const result = userSchema.safeParse(await response.json());

if (!result.success) {
  console.error("Response doesn't match the expected shape:", result.error.issues);
} else {
  console.log(result.data.name); // the data has already been validated here
}

Prefer safeParse when you want to handle the error without throwing: it returns an object with success and, on failure, the list of problems found and which field they're in.

Refining the schema

The tool infers basic types from the example: text becomes z.string(), numbers become z.number(), and so on. More specific rules are up to you:

TypeScript: refined schema
const userSchema = z.object({
  id: z.number().int().positive(),
  name: z.string().min(1),
  email: z.string().email(),
  active: z.boolean(),
  tags: z.array(z.string()),
  nickname: z.string().optional(),     // may be missing from the response
  lastLogin: z.string().nullable(),    // may come back as null
});

Fields that only sometimes appear

An example doesn't show which fields are optional. Compare it against the API's documentation and use .optional() and .nullable() where it makes sense.

Already have the interfaces? Convert straight from TypeScript

If you already wrote the types, use the TypeScript → Zod conversion: paste the interface and get the equivalent schema back, without going through a sample JSON. Unlike inferring from JSON, here the tool sees what the types actually say, so it preserves optional fields, nullable values and literal-value unions:

Input (TypeScript interface)
type Role = "admin" | "user";

interface User {
  id: number;
  name: string;
  email?: string;
  role: Role;
  nickname: string | null;
}
Output (Zod from TypeScript)
const userSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().optional(),
  role: z.enum(["admin", "user"]),
  nickname: z.string().nullable(),
});
  • email?: string became .optional().
  • "admin" | "user" became z.enum([...]), even going through the Role alias.
  • string | null became .nullable().

More advanced types (generics, Partial, Record, tuples, intersections with &, and the Date type) still come out simplified as z.unknown(); review the result in those cases.

When to use just types, and when to use Zod

  • Just types: for data that originates inside your own application and that you control.
  • Zod: at every boundary with the outside world, like API responses, forms, uploaded files, environment variables, and localStorage content.

Frequently asked questions

Do I need to install Zod?

Yes. The generated code uses the Zod library, which you install with npm install zod. The tool only generates the schemas; importing z is on you.

Does Zod replace TypeScript interfaces?

In practice, yes. With z.infer you get the TypeScript type straight from the schema, so you keep a single definition instead of two.

What's the difference between Zod and JSON Schema?

Zod is a validation library for TypeScript. JSON Schema is a language-independent standard, useful for documentation and for sharing contracts with other systems. Transform also converts JSON into JSON Schema.

Is the generated schema final?

It's a starting point. It describes the shape of the example you pasted, with basic types. Rules like email format, minimum values, optional and nullable fields are yours to add afterward.

Try it now

Free, no sign-up, and everything happens in your browser.

Open Transform