author avatar

aman.suhag

Thu Sep 26 2024

Schema Validation with Zod: Why and How?
When building APIs, validating the structure and content of incoming requests is crucial for security, consistency, and reliability. Using a library like zod allows you to define schemas that describe the expected data format and then easily validate incoming data. Here’s how and why we use it in a Next.js API.
Why Validate?
1. Security: Ensure only well-formed data reaches your application, preventing injection attacks or bad data.
2. Consistency: Guarantees that the data has the correct shape, making it easier to work with.
3. Error Handling: Helps provide meaningful error messages when the validation fails.
Example: Standup Schema Validation
Using zod, we can define a schema for our "standup" object and use it to validate incoming requests in our API route.


import { z } from "zod";

// Define a schema for the standup data
const standupSchema = z.object({
  name: z.string().trim().nonempty(),
  days: z.number().array().min(1).max(7),
  time: z.string().datetime(),
  postStandupTime: z.string().datetime(),
  standupLead: z
    .object({
      name: z.string().trim().nonempty(),
      id: z.string(),
    })
    .required(),
  questions: z
    .array(z.object({ text: z.string().min(1), isActive: z.boolean() }))
    .min(1),
  channel: z.object({
    name: z.string().trim().nonempty(),
    id: z.string(),
  }),
  members: z
    .array(
      z.object({
        name: z.string().trim().nonempty(),
        id: z.string(),
      })
    )
    .min(1),
  isActive: z.union([z.boolean(), z.undefined()]),
  schedulerId: z.string().optional(),
  timezone: z.string().min(1),
  postType: z.string().min(1),
});

export type StandupDetail = z.infer;


Validating Incoming Data
In your API route, you can use safeParse to validate the request body against the schema. This ensures the data is valid before proceeding with further logic.


export async function PATCH(req: NextRequest) {
  const body = await req.json();
  
  // Validate the request body using the schema
  const response = standupSchema.safeParse(body);
  
  if (!response.success) {
    const { errors } = response.error;
    return NextResponse.json(
      { error: { message: "Invalid Payload", errors } },
      { status: 400 }
    );
  }
  
  // If successful, extract the validated data
  const {
    name,
    days,
    time,
    postStandupTime,
    questions,
    channel,
    members,
    isActive,
    timezone,
    standupLead,
    postType,
  }: StandupDetail = response.data;

  // Proceed with your logic using the validated data
}


Key Benefits -
Type Safety: With zod and TypeScript, you get strong typing, ensuring that the validated data has the expected shape.
Automatic Error Handling: If the validation fails, you can easily catch errors and send meaningful feedback.
Data Consistency: Guarantees that the incoming data adheres to a predefined structure, making your API more reliable and robust.
#zod #type-security #json