Установка и настройка окружения

Библиотека Joi распространяется через npm и используется в среде Node.js для декларативной валидации данных. Перед установкой требуется наличие установленного Node.js и доступного менеджера пакетов npm или yarn.

Установка через npm выполняется командой:

npm install joi

При использовании yarn:

yarn add joi

После установки пакет появляется в node_modules, а зависимости фиксируются в package.json, что обеспечивает воспроизводимость окружения на других машинах.


Подключение библиотеки в проект

Joi поддерживает как CommonJS, так и ES Modules, что позволяет интеграцию в различные типы проектов.

CommonJS (Node.js стандарт)

const Joi = require('joi');

ES Modules

import Joi from 'joi';

При использовании ES Modules важно, чтобы в package.json было указано:

{
  "type": "module"
}

Базовая структура схемы валидации

Основой работы Joi является схема (schema), описывающая структуру и правила проверки данных. Схема создаётся через цепочку методов, соответствующих типам данных.

Пример схемы объекта:

const schema = Joi.object({
  name: Joi.string(),
  age: Joi.number(),
  email: Joi.string().email()
});

Каждое поле описывается отдельным валидатором, который определяет допустимый тип и ограничения.


Проверка данных

Для проверки используется метод validate, возвращающий результат валидации и описание ошибок при их наличии.

const result = schema.validate({
  name: 'Alex',
  age: 25,
  email: 'alex@example.com'
});

Структура результата:

  • value — нормализованные данные
  • error — объект ошибки при несоответствии схемы

Настройка поведения валидации

Joi позволяет изменять поведение проверки через дополнительные параметры:

const result = schema.validate(data, {
  abortEarly: false,
  allowUnknown: true,
  stripUnknown: true
});

Ключевые опции:

  • abortEarly — прекращение проверки после первой ошибки
  • allowUnknown — разрешение неизвестных полей
  • stripUnknown — удаление лишних полей из результата

Использование строгой типизации данных

Joi поддерживает строгие ограничения типов и значений.

const schema = Joi.object({
  age: Joi.number().integer().min(0).max(120).required(),
  username: Joi.string().alphanum().min(3).max(30).required()
});

Поддерживаются цепочки ограничений:

  • required() — обязательное поле
  • min() и max() — диапазоны значений
  • integer() — целые числа
  • alphanum() — только буквы и цифры

Подключение в серверных приложениях

Наиболее частое применение Joi — валидация входящих данных в API, например в приложениях на Express.

import express from 'express';
import Joi from 'joi';

const app = express();
app.use(express.json());

const schema = Joi.object({
  email: Joi.string().email().required(),
  password: Joi.string().min(8).required()
});

app.post('/register', (req, res) => {
  const { error } = schema.validate(req.body);

  if (error) {
    return res.status(400).json({
      message: error.details[0].message
    });
  }

  res.status(200).send('OK');
});

Валидация выполняется до основной бизнес-логики, что снижает риск обработки некорректных данных.


Настройка повторного использования схем

Схемы можно выделять в отдельные модули для повторного использования в разных частях приложения.

// validation/userSchema.js
import Joi from 'joi';

export const userSchema = Joi.object({
  username: Joi.string().min(3).required(),
  email: Joi.string().email().required()
});

Импорт в других файлах:

import { userSchema } from './validation/userSchema.js';

Использование базовой конфигурации Joi

Joi поддерживает глобальные настройки через defaults, позволяющие централизованно задавать поведение схем.

const base = Joi.defaults((schema) => {
  return schema.options({
    abortEarly: false
  });
});

Дальнейшие схемы создаются на основе базовой конфигурации:

const schema = base.object({
  name: Joi.string().required()
});

Совместимость с TypeScript

При использовании TypeScript часто подключается пакет типов:

npm install --save-dev @types/joi

Однако в современных версиях Joi типизация встроена частично, и многие проекты обходятся без дополнительных деклараций.


Обработка ошибок валидации

Ошибки Joi имеют структурированный формат, позволяющий извлекать детали:

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

if (error) {
  console.log(error.details);
}

Каждый элемент details содержит:

  • message — текст ошибки
  • path — путь к полю
  • type — тип нарушения правила

Композиция и вложенные объекты

Joi поддерживает сложные структуры данных с вложенными объектами и массивами.

const schema = Joi.object({
  user: Joi.object({
    name: Joi.string(),
    contacts: Joi.array().items(Joi.string().email())
  })
});

Такая модель позволяет описывать сложные JSON-структуры без дополнительной логики.


Переиспользование правил и расширение схем

Joi позволяет создавать расширенные правила через extend, добавляя собственные валидаторы.

const customJoi = Joi.extend((joi) => ({
  type: 'positiveInt',
  base: joi.number().integer(),
  validate(value, helpers) {
    if (value <= 0) {
      return { value, errors: helpers.error('positiveInt.base') };
    }
  }
}));

Работа с асинхронной валидацией

Joi поддерживает асинхронную проверку, например при обращении к базе данных:

const schema = Joi.object({
  username: Joi.string().external(async (value) => {
    const exists = await checkUser(value);
    if (exists) {
      throw new Error('User already exists');
    }
    return value;
  })
});

Асинхронная валидация выполняется через validateAsync.

await schema.validateAsync(data);