Add Type Safety to your APIs with Zod

Lee Robinson

Paul Berthelot / January 10, 2023

3 min read–––

Why using Zod?

As a developer, one of the most important things I need to do when building an API is ensure that the data coming in is valid and safe to use. To accomplish this, I turn to a library called Zod.

Zod is a JavaScript library for creating simple, yet powerful and expressive, schema validation. It allows me to define the shape of the data I expect to receive in my API, and then automatically checks that incoming data conforms to that shape.

One of the things I love about Zod is how simple and easy it is to use. Defining a schema is as simple as creating an object with the properties and types I expect. For example, if I expect to receive an email in a request to my API, my schema might look like this:

const inputSchema = z.object({ email: z.string() });

Once I have my schema defined, I can use it to validate incoming data with a single line of code:

const { email } = inputSchema.parse({ email: req.query.email });

If the data doesn't match the schema, Zod will throw an error that I can easily catch and handle. This makes it simple to ensure that my API only processes data that is guaranteed to be valid.

Integrate Zod with Next.js

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import z from 'zod';

type Data = {
  success: boolean;
  error?: string;
  data?: any;
};

const inputSchema = z.object({
  email: z.string(),
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  try {
    const { email } = inputSchema.parse({ email: req.query.email });
    // you can be sure that 'email' is a string from here...
    res.status(200).json({ success: true });
  } catch (error: any) {
    return res.status(500).json({ success: false, error });
  }
}

Note here that I also typed the response of my api to be more consistent and reliable. You can do this by defining a Data type and pass it to the NextApiResponse.

Powerful validation options

Another thing I appreciate about Zod is that it has a ton of built-in validation options, like min/max length for strings, minimum/maximum values for numbers, and regular expressions for matching patterns. This means I can write very specific validation rules that match exactly what I need for my API, and nothing more.

const SUBSCRIPTIONS = ["HOBBY", "SCALER", "TEAM", "ENTERPRISE"] as const;
const SubscriptionEnum = z.enum(SUBSCRIPTIONS);

z.object({
  title: z.string().min(5),
  description: z.string().nullable(),
  countViews: z.number(),
  subscription: z.enum(SubscriptionEnum),
  tags: z
    .object({
      value: z.string(),
      label: z.string(),
      color: z.string(),
    })
    .array(),
});

Final thoughts

All in all, I use Zod to validate inputs in my API built with Next.js because it's simple, powerful, and flexible. It gives me peace of mind knowing that the data coming into my API is guaranteed to be valid and safe to use, without adding a lot of extra code or complexity. This makes it easy to catch errors early and avoid introducing bugs into your code. Additionally, because Zod is written in TypeScript, you can take advantage of its powerful type system to ensure that your validations are accurate and comprehensive.

Subscribe to the newsletter

Get emails from me about web development, tech trends, and advices for founders.

24 subscribers