Библиотека Joi представляет собой инструмент декларативной валидации данных, ориентированный на описание схем и проверку соответствия входящих значений заданным правилам. Она широко применяется в серверных приложениях Node.js, особенно в связке с REST API, где требуется строгий контроль структуры входящих запросов.
Joi опирается на концепцию схем (schema-based validation), где каждое значение описывается через набор правил. Схема определяет:
Валидация выполняется путём сопоставления входных данных со схемой.
Библиотека устанавливается через npm:
npm install joi
Использование в коде:
const Joi = require('joi');
В современных версиях также поддерживается ESM-синтаксис:
import Joi from 'joi';
const schema = Joi.string();
Расширенные ограничения:
const schema = Joi.string()
.min(3)
.max(30)
.required();
Дополнительные проверки:
Joi.string().email();
Joi.string().uri();
Joi.string().pattern(/^[a-z]+$/);
const schema = Joi.number();
Ограничения:
Joi.number().min(0).max(100);
Joi.number().integer();
Joi.number().positive();
Joi.boolean();
const schema = Joi.array();
Содержимое массива:
Joi.array().items(Joi.string());
Ограничения:
Joi.array().min(1).max(5);
Joi.array().unique();
Наиболее часто используемый тип в Joi.
const schema = Joi.object({
name: Joi.string().required(),
age: Joi.number().min(18)
});
const schema = Joi.object({
username: Joi.string().min(3).required()
});
const result = schema.validate({ username: 'alex' });
Результат содержит:
const result = await schema.validateAsync(data);
При ошибке выбрасывается исключение.
Joi формирует структурированные ошибки, содержащие:
Пример:
{
message: '"username" is required',
path: ['username'],
type: 'any.required'
}
По умолчанию Joi прекращает проверку после первой ошибки. Для получения полного списка ошибок:
schema.validate(data, { abortEarly: false });
Разрешает наличие дополнительных полей:
Joi.object().unknown(true);
Удаляет неизвестные поля:
Joi.object({
name: Joi.string()
}).unknown(false).options({ stripUnknown: true });
Joi.string().min(3).messages({
'string.min': 'Слишком короткая строка'
});
Сообщения могут быть привязаны к конкретным типам ошибок.
Позволяет изменять правила в зависимости от значения другого поля.
const schema = Joi.object({
role: Joi.string().valid('admin', 'user'),
access: Joi.string().when('role', {
is: 'admin',
then: Joi.valid('all'),
otherwise: Joi.valid('limited')
})
});
const schema = Joi.alternatives().try(
Joi.string(),
Joi.number()
);
Используется для поддержки нескольких допустимых типов.
const schema = Joi.string().custom((value, helpers) => {
if (value === 'forbidden') {
return helpers.error('any.invalid');
}
return value;
});
Joi позволяет комбинировать схемы:
const base = Joi.string().min(3);
const extended = base.max(10).required();
const schema = Joi.object({
user: Joi.object({
name: Joi.string(),
age: Joi.number()
})
});
const schema = Joi.array().items(
Joi.object({
id: Joi.number(),
title: Joi.string()
})
);
const schema = Joi.object({
role: Joi.string().default('user')
});
При отсутствии поля значение автоматически подставляется.
Joi способен преобразовывать входные данные:
Joi.number().integer().convert();
Пример: строка “123” может быть преобразована в число.
Joi.object().strict();
Отключает автоматическое приведение типов.
Joi.object({
email: Joi.string().required()
});
Типичная структура запроса:
const schema = Joi.object({
body: Joi.object({
username: Joi.string().min(3).required(),
password: Joi.string().min(6).required()
}),
query: Joi.object({
page: Joi.number().default(1)
})
});
Схемы могут быть вынесены и повторно использованы:
const userSchema = Joi.object({
name: Joi.string(),
age: Joi.number()
});
const createUserSchema = userSchema.required();
Поддерживается создание собственных расширений:
const customJoi = Joi.extend((joi) => ({
type: 'evenNumber',
base: joi.number(),
validate(value, helpers) {
if (value % 2 !== 0) {
return { value, errors: helpers.error('number.even') };
}
}
}));
Joi.object({
password: Joi.string(),
confirmPassword: Joi.string().valid(Joi.ref('password'))
});
Joi.string().allow(null);
Joi.string().optional();
const schema = Joi.object({
name: Joi.string().required()
}).prefs({ convert: true });
const schema = Joi.object({
users: Joi.array().items(
Joi.object({
id: Joi.number(),
tags: Joi.array().items(Joi.string())
})
)
});
Ошибки возвращаются с полным путём:
Это позволяет точно локализовать проблему в данных.
const schema = Joi.object({
min: Joi.number(),
max: Joi.number().min(Joi.ref('min'))
});
Joi.date();
Joi.date().iso();
Joi.date().greater('2020-01-01');
Joi.object({
isActive: Joi.boolean(),
lastLogin: Joi.date().when('isActive', {
is: true,
then: Joi.required()
})
});
Joi оптимизирован для серверной валидации и используется в сценариях:
Сложные схемы могут влиять на производительность при глубокой вложенности и большом объёме данных, что требует структурного проектирования схем.
Используются подходы: