Cover Image for How to Implement Request Body Validation in a Next.js API using a ‘/validation’ Folder Structure
Abdulrahman Muhialdeen
Abdulrahman Muhialdeen

How to Implement Request Body Validation in a Next.js API using a ‘/validation’ Folder Structure

When building an API, it is important to ensure that the data sent in the request body is valid and meets certain criteria. This can be accomplished by implementing a request body validation layer...

INTRODUCTION

When building an API, it is important to ensure that the data sent in the request body is valid and meets certain criteria. This can be accomplished by implementing a request body validation layer, which checks the incoming data against a set of predefined rules before allowing it to be processed. In this article, we will explore how to use a /validation folder structure, Schema.ts and Validators.ts files to implement request body validation in a Next.js API.


Section 1: Setting up the ‘/validation’ folder structure

The first step in implementing request body validation in a Next.js API is to create a /validation folder structure at the root of your project. This folder will contain two files: Schema.ts and Validators.ts.

Section 2: Creating a validation schema

The Schema.ts the file is responsible for defining a validation schema for your data. This schema is used to define the rules that incoming data must adhere to to be considered valid. In our example, we will create a validation schema for user data.

type ValidationFunction<T> = (value: T) => boolean;
type ValidationsList<T> =Array<{ name: keyof T, fn: ValidationFunction<T> }>;
 
export class ValidationSchema<T> {
  private validations:ValidationsList<T> ;
 
  constructor(validations?:ValidationsList<T>) {
    this.validations = validations ?? [];
  }
 
  addValidation(name: keyof T, fn: ValidationFunction<T>) {
    this.validations.push({ name, fn });
  }
 
  validate(values: T): Array<string> {
    const errors: Array<string> = [];
    
    for (const validation of this.validations) {
      if (!validation.fn(values)) {
        errors.push(`Invalid value in property :${String(validation.name)}`);
      }
    }
 
    return errors;
  }
}

We will define our ValidationSchema class with a generic type of IUser, which will represent the shape of our user data. The ValidationSchema class contains an array of ValidationsList, which is a list of validation rules that we will define.

Section 3: Creating validation functions

The Validators.ts the file is where we will define our validation functions. These functions take in the incoming data and use the ValidationSchema class to validate the data against the rules we defined in Schema.ts. In our example, we will create a function called UserValidator, which will validate incoming user data.

import { IUser } from 'types/UserType';
import { ValidationSchema } from './Schema';
 
function UserValidator(data: IUser): Array<string> {
  const userSchema = new ValidationSchema<IUser>([
    { name: "name", fn: (value) => typeof value.name === "string" && value.name.length > 0 },
    { name: "email", fn: (value) => typeof value.email === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.email) },
    { name: "age", fn: ({ age }) => typeof age === "number" && age >= 18 && age <= 120 },
  ]);
 
  const errors = userSchema.validate(data);
  return errors;
}
 
export const Validators = {
  UserValidator
}

Section 4: Implementing request body validation in the Next.js API

Now that we have our validation schema and validation functions in place, we can implement request body validation in our Next.js API. We will create an API route handler that uses our UserValidator function to validate incoming data before processing it.

import { NextApiRequest, NextApiResponse } from 'next';
import { Validators } from '../../validation/Validators';
import { IUser } from '../../types/UserType';
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    const errors = Validators.UserValidator(req.body as IUser);
 
    if (errors.length === 0) {
      // process the user's data
      res.status(200).json({ message: "Data is valid!" });
    } else {
      res.status(400).json({ errors });
    }
  } else {
    res.status(405).json({ message: "Method not allowed" });
  }
}

Conclusion:

In conclusion, implementing request body validation in a Next.js API is an important step in ensuring the integrity of your data. By using a /validation folder structure, Schema.ts, and Validators.ts files, we can easily define a validation schema and create validation functions to validate incoming data. This approach helps to keep our code organized and makes it easy to maintain and update our validation rules as our API evolves over time.