C Camila Sironi

Building RESTful APIs with Express and Zod: A Practical Guide

Introduction

This post explores how to build robust RESTful APIs using Express, a popular Node.js framework, and Zod, a TypeScript-first schema declaration and validation library. We'll focus on request validation using middleware, ensuring data integrity and improving the overall reliability of your API.

The Problem: Unvalidated Request Data

Without proper validation, your API endpoints are vulnerable to receiving invalid data. This can lead to unexpected errors, security vulnerabilities, and data corruption. Manually validating each request is tedious and error-prone.

The Solution: Middleware-Based Validation with Zod

We can leverage Express middleware and Zod to create a reusable and type-safe validation pipeline. This approach keeps our route handlers clean and focused on business logic.

Implementing the Validation Middleware

First, define a generic middleware function that takes a Zod schema as input:

import { Request, Response, NextFunction } from 'express';
import { AnyZodObject } from 'zod';

const validate = (schema: AnyZodObject) => async (req: Request, res: Response, next: NextFunction) => {
  try {
    await schema.parseAsync({
      body: req.body,
      query: req.query,
      params: req.params,
    });
    return next();
  } catch (error: any) {
    return res.status(400).json(error);
  }
};

export default validate;

This validate middleware uses Zod to parse and validate the request body, query parameters, and route parameters against a provided schema. If validation fails, it returns a 400 Bad Request error with the Zod error details.

Defining Zod Schemas

Next, define Zod schemas for each request type. For example, a schema for creating a new user:

import { z } from 'zod';

const createUserSchema = z.object({
  body: z.object({
    username: z.string().min(3).max(50),
    email: z.string().email(),
    password: z.string().min(8),
  }),
});

export type CreateUserInput = z.infer<typeof createUserSchema>["body"];

export default createUserSchema;

This schema defines the expected structure and types for the request body, including constraints on the username, email, and password fields.

Applying the Middleware to Routes

Finally, apply the validation middleware to your Express routes:

import express, { Request, Response } from 'express';
import validate from '../middleware/validate';
import createUserSchema, { CreateUserInput } from '../schemas/createUserSchema';

const router = express.Router();

router.post('/users', validate(createUserSchema), async (req: Request<{}, {}, CreateUserInput>, res: Response) => {
  try {
    // Process the validated request data
    const userData = req.body;
    // Create user in database (example)
    // const newUser = await createUser(userData);
    return res.status(201).json({ message: 'User created successfully' });
  } catch (error) {
    console.error(error);
    return res.status(500).json({ message: 'Internal server error' });
  }
});

export default router;

By wrapping the route handler with the validate(createUserSchema) middleware, we ensure that only valid requests reach the handler function. The handler now receives type-safe data based on the CreateUserInput type.

Benefits of This Approach

  • Data Integrity: Ensures that your API receives only valid data.
  • Type Safety: Leverages TypeScript's type system for compile-time checking.
  • Code Reusability: The validation middleware can be applied to multiple routes.
  • Clean Code: Separates validation logic from route handling logic.

Conclusion

Using Express middleware with Zod provides a powerful and elegant solution for request validation in your Node.js APIs. This approach improves data integrity, enhances code maintainability, and reduces the risk of runtime errors. As a next step, try implementing this pattern in your own projects and explore Zod's advanced features for complex validation scenarios.


Generated with Gitvlg.com

Building RESTful APIs with Express and Zod: A Practical Guide
C

Camila Sironi

Author

Share: