Data Validation in Node.js with Joi: A Complete Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Data Validation in Node.js with Joi

In modern web applications on Node.js, data validation is a critically important stage of request processing. Errors in data can lead to vulnerabilities, incorrect operation, or server crashes. One of the most powerful and popular libraries for this task is Joi (pronounced "joy"). It allows you to describe data schemas and check their compliance with specified rules.



What is Joi?

Joi is a library for describing schemas and validating JavaScript objects. It is especially popular in the Node.js ecosystem, where it is often used together with Express, Hapi, or Fastify. Joi provides a simple and expressive API for specifying types, required fields, ranges, regular expressions, and custom checks.



Installation

Installing Joi via npm:

npm install joi


Basic Example

Let's create a schema for validating user data:

const Joi = require('joi');

const schema = Joi.object({ username: Joi.string() .alphanum() .min(3) .max(30) .required(), password: Joi.string() .pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')), email: Joi.string() .email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })});

const data = { username: 'user123', password: 'pass123', email: 'user@example.com'};

const { error, value } = schema.validate(data);

if (error) { console.log('Validation error:', error.details);} else { console.log('Data is valid:', value);}


Basic Methods and Rules

Joi supports many types and modifiers:

  • Data types: Joi.string(), Joi.number(), Joi.boolean(), Joi.date(), Joi.array(), Joi.object().
  • Required: .required() — field is mandatory.
  • Constraints: .min(), .max(), .length() — for strings and arrays.
  • Regular expressions: .pattern(regex) — pattern matching.
  • Email and URL: .email(), .uri() — built-in validators.
  • Custom messages: .messages() — override default errors.


Validating Nested Objects and Arrays

Joi handles complex structures well:

const addressSchema = Joi.object({    street: Joi.string().required(),    city: Joi.string().required(),    zip: Joi.string().pattern(/^\\d{5}$/)});

const userSchema = Joi.object({ name: Joi.string().required(), age: Joi.number().integer().min(18).max(120), addresses: Joi.array().items(addressSchema).min(1)});

const userData = { name: 'Anna', age: 25, addresses: [ { street: 'Nevsky Ave.', city: 'SPb', zip: '191011' } ]};

const result = userSchema.validate(userData);console.log(result.error ? result.error.details : 'OK');


Error Handling

On validation error, Joi returns an error.details object — an array with a detailed description of each error:

if (result.error) {    result.error.details.forEach(detail => {        console.log(`Field: ${detail.path.join('.')}, message: ${detail.message}`);    });}


Using with Express

Joi is often used in middleware for request validation:

const express = require('express');const Joi = require('joi');const app = express();

app.use(express.json());

const validateUser = (req, res, next) => { const schema = Joi.object({ name: Joi.string().required(), email: Joi.string().email().required() }); const { e

Recommendations