REST API Request Validation

In this article we will look at how to validate POST requests to the REST API using Joi library. Joi lets you describe your data using a simple, intuitive, and readable language. We will also look at how to turn Joi errors into 422 Validation Error API responses.

Describe REST API Request Shema with Joi

We will be validating POST /v1/travels REST API request in travels API project. You can find the project in this GitHub repository. For more in depth explanation, please watch the video below.

Let’s describe the schema of this request with Joi. In the middleware folder let’s create requestSchemas.ts file and put the following code.

import Joi from "joi";

export const createTravelSchema = Joi.object({
  name: Joi.string().min(3).max(30).required(),
  description: Joi.string(),
  number_of_days: Joi.number().integer().greater(0).required(),
  is_public: Joi.bool().default(true),
});

In the code above we describe incoming POST Request fields using Joi methods. Joi has a lot of methods, and you can find the ones for your specific use cases in Joi documentation.

Validate Joi Schema in the Middleware

Next in the middleware folder let’s create validateRequest.ts middleware. We will use validateAsync Joi method to validate the request body. If validateAsync throws an error we will catch it and pass it to the ErrorHandler.

import { NextFunction, Request, Response } from "express";
import { ObjectSchema } from "joi";

export default function validateRequest(schema: ObjectSchema) {
  return async function validator(
    req: Request,
    res: Response,
    next: NextFunction
  ) {
    if (!req.body) {
      next();
    }
    try {
      await schema.validateAsync(req.body, { abortEarly: false });
    } catch (error) {
      next(error);
      return;
    }
    next();
  };
}

Add Request Validation Middleware to REST API Route

Finally, we will add validateRequest middleware we created to create travel route in routes/v1/travels/index.ts file.

import express, { Router } from "express";
import { listTravels, getTravel, createTravel } from "./controller";
import validateRequest from "../../../middleware/validateRequest";
import { createTravelSchema } from "../../../middleware/requestSchemas";

const travels: Router = express.Router();

travels.get("/", listTravels);
travels.get("/:id", getTravel);
travels.post("/", validateRequest(createTravelSchema), createTravel);

export default travels;

Return Joi Error as 422 REST API Validation Errors

After we catch Joi validation errors, we need to update ErrorHandler code to return 422 Validation errors to the users. First we create ValidationError type in types.d.ts file.

type ErrorCode = "ERR_NF" | "ERR_REMOTE" | "NOT_IMPL" | "ERR_VALID";

type ValidationError = {
  error: {
    message: string;
    code: ErrorCode;
    errors: Array<{ message: string }>;
  };
};

Then on line 15 of ErroHandler.ts file we add the following if block.

if (Joi.isError(error)) {
    const validationError: ValidationError = {
      error: {
        message: "Validation error",
        code: "ERR_VALID",
        errors: error.details.map((item) => ({
          message: item.message,
        })),
      },
    };
    return res.status(422).json(validationError);
  }

Conclusion

REST API request validation plays a critical role in building secure, reliable, and efficient web services. Joi library let’s you easily describe requests’ payloads and validate them. If request validation fails, Joi errors can be handled to return 422 validation errors to the API users.

References

Joi NPM Package

Joi Documentation

Share this article

Posted

in

by