JSON payload — это структура данных, передаваемая между клиентом и сервером в формате JSON. Чаще всего payload содержится в HTTP-запросах:
{
"email": "admin@example.com",
"password": "123456",
"age": 25
}
Основная задача валидации — проверить:
Библиотека Validator.js предоставляет большой набор функций для проверки строковых данных.
npm install validator
CommonJS:
const validator = require('validator');
ES Modules:
import validator from 'validator';
Validator.js работает преимущественно со строками.
Например:
validator.isEmail('admin@example.com');
Но:
validator.isEmail(12345);
вызовет ошибку, поскольку функция ожидает строку.
Поэтому при валидации JSON payload почти всегда требуется:
undefined и null.Пример запроса регистрации пользователя:
{
"name": "Alex",
"email": "alex@example.com",
"password": "StrongPass123",
"age": 30,
"website": "https://example.com"
}
Проверка должна удостовериться, что:
| Поле | Проверка |
|---|---|
| name | не пустое |
| корректный email | |
| password | минимальная длина |
| age | число в допустимом диапазоне |
| website | корректный URL |
import validator from 'validator';
function validateUser(data) {
const errors = {};
if (!data.name || validator.isEmpty(data.name)) {
errors.name = 'Name is required';
}
if (!data.email || !validator.isEmail(data.email)) {
errors.email = 'Invalid email';
}
if (!data.password || !validator.isLength(data.password, { min: 8 })) {
errors.password = 'Password too short';
}
return errors;
}
Использование:
const payload = {
name: 'Alex',
email: 'wrong-email',
password: '123'
};
const errors = validateUser(payload);
console.log(errors);
Результат:
{
email: 'Invalid email',
password: 'Password too short'
}
if (!data.email)
Недостаток такого подхода:
0
false
''
null
undefined
все считаются ложными значениями.
Поэтому лучше выполнять более точные проверки.
undefined и
nullif (data.email === undefined || data.email === null)
validator.isEmpty(data.email);
Важно учитывать:
validator.isEmpty(' ');
вернёт false, поскольку строка содержит пробелы.
validator.isEmpty(data.email.trim());
Payload:
{
"email": null
}
Вызов:
validator.isEmail(null);
приведёт к ошибке.
function normalize(value) {
if (value === undefined || value === null) {
return '';
}
return String(value);
}
Использование:
const email = normalize(data.email);
if (!validator.isEmail(email)) {
errors.email = 'Invalid email';
}
validator.isEmail('admin@example.com');
Результат:
true
if (!validator.isEmail(normalize(data.email))) {
errors.email = 'Invalid email';
}
validator.isEmail(email, {
allow_utf8_local_part: false,
require_tld: true
});
| Параметр | Назначение |
|---|---|
| require_tld | требует доменную зону |
| allow_ip_domain | разрешает IP вместо домена |
| allow_utf8_local_part | UTF-8 символы |
| ignore_max_length | игнорирует ограничение длины |
validator.isURL('https://example.com');
if (!validator.isURL(normalize(data.website))) {
errors.website = 'Invalid URL';
}
validator.isURL(url, {
protocols: ['https'],
require_protocol: true
});
Validator.js работает со строками.
validator.isInt('25');
validator.isInt('25', {
min: 18,
max: 60
});
const age = normalize(data.age);
if (!validator.isInt(age, { min: 18, max: 120 })) {
errors.age = 'Invalid age';
}
validator.isFloat('19.99');
validator.isFloat('19.99', {
min: 0,
max: 1000
});
const price = normalize(data.price);
if (!validator.isFloat(price, { min: 0 })) {
errors.price = 'Invalid price';
}
validator.isLength('password123', {
min: 8,
max: 32
});
const username = normalize(data.username);
if (!validator.isLength(username, { min: 3, max: 20 })) {
errors.username = 'Username length invalid';
}
validator.isAlphanumeric('alex123');
if (!validator.isAlphanumeric(username)) {
errors.username = 'Only letters and numbers allowed';
}
validator.isUUID(id, 4);
const userId = normalize(data.userId);
if (!validator.isUUID(userId)) {
errors.userId = 'Invalid UUID';
}
Иногда payload содержит JSON-строку.
{
"settings": "{\"theme\":\"dark\"}"
}
validator.isJSON(data.settings);
if (!validator.isJSON(normalize(data.settings))) {
errors.settings = 'Invalid JSON';
}
validator.isISO8601('2025-01-01');
const birthDate = normalize(data.birthDate);
if (!validator.isISO8601(birthDate)) {
errors.birthDate = 'Invalid date';
}
validator.isMobilePhone('+77001234567', 'any');
const phone = normalize(data.phone);
if (!validator.isMobilePhone(phone, 'any')) {
errors.phone = 'Invalid phone number';
}
validator.isMobilePhone(phone, 'kk-KZ');
Validator.js содержит не только валидаторы, но и санитайзеры.
Удаление пробелов:
validator.trim(' admin@example.com ');
Экранирование HTML:
validator.escape('<script>alert(1)</script>');
Результат:
<script>alert(1)</script>
validator.normalizeEmail('ADMIN@EXAMPLE.COM');
function sanitizeUserPayload(data) {
return {
name: validator.trim(normalize(data.name)),
email: validator.normalizeEmail(normalize(data.email)),
website: validator.trim(normalize(data.website))
};
}
import validator from 'validator';
function normalize(value) {
if (value === undefined || value === null) {
return '';
}
return String(value);
}
function validateUserPayload(data) {
const errors = {};
const name = validator.trim(normalize(data.name));
const email = validator.normalizeEmail(normalize(data.email));
const password = normalize(data.password);
const age = normalize(data.age);
if (validator.isEmpty(name)) {
errors.name = 'Name required';
}
if (!validator.isEmail(email || '')) {
errors.email = 'Invalid email';
}
if (!validator.isLength(password, { min: 8 })) {
errors.password = 'Password too short';
}
if (!validator.isInt(age, { min: 18, max: 120 })) {
errors.age = 'Invalid age';
}
return {
isValid: Object.keys(errors).length === 0,
errors
};
}
{
"users": [
{
"email": "admin@example.com"
},
{
"email": "wrong-email"
}
]
}
function validateUsers(users) {
const errors = [];
users.forEach((user, index) => {
if (!validator.isEmail(normalize(user.email))) {
errors.push({
index,
field: 'email',
message: 'Invalid email'
});
}
});
return errors;
}
{
"profile": {
"contacts": {
"email": "admin@example.com"
}
}
}
const email = normalize(
data.profile?.contacts?.email
);
if (!validator.isEmail(email)) {
errors.email = 'Invalid email';
}
import validator from 'validator';
function validateRegister(req, res, next) {
const errors = {};
const email = normalize(req.body.email);
const password = normalize(req.body.password);
if (!validator.isEmail(email)) {
errors.email = 'Invalid email';
}
if (!validator.isLength(password, { min: 8 })) {
errors.password = 'Password too short';
}
if (Object.keys(errors).length > 0) {
return res.status(400).json({
errors
});
}
next();
}
app.post('/register', validateRegister, controller);
{
email: 'Invalid email'
}
{
email: {
code: 'INVALID_EMAIL',
message: 'Email format invalid'
}
}
[
{
field: 'email',
message: 'Invalid email'
}
]
function isRequired(value) {
return !validator.isEmpty(
normalize(value).trim()
);
}
function isValidEmail(value) {
return validator.isEmail(
normalize(value)
);
}
Использование:
if (!isRequired(data.email)) {
errors.email = 'Required';
}
Validator.js выполняет только синхронные проверки.
Но часто требуется:
async function validate(data) {
const errors = {};
if (!validator.isEmail(normalize(data.email))) {
errors.email = 'Invalid email';
}
const exists = await User.exists({
email: data.email
});
if (exists) {
errors.email = 'Email already used';
}
return errors;
}
Ошибка:
validator.isEmail(undefined);
Решение:
normalize(value);
Ошибка:
validator.isEmail(' admin@example.com ');
Результат:
false
Правильно:
validator.isEmail(
validator.trim(email)
);
Даже если frontend уже проверяет данные:
<input type="email">
сервер обязан выполнять собственную валидацию.
Наличие корректного email не означает существование адреса.
test@test.test
формально валиден.
validateUserPayload()
validateProductPayload()
validateOrderPayload()
Преимущества:
trim()
escape()
normalizeEmail()
isEmail()
isInt()
isURL()
errors.email = 'Invalid email';
Validator.js работает быстро, поскольку:
Однако при больших payload:
{
"users": [...]
}
важно:
{
"email": "admin@example.com",
"role": "admin",
"isRoot": true
}
Иногда необходимо запрещать лишние поля.
const allowedFields = [
'email',
'password'
];
const unknownFields = Object.keys(data)
.filter(key => !allowedFields.includes(key));
if (unknownFields.length > 0) {
errors.fields = 'Unknown fields detected';
}
const password = normalize(data.password);
const strong =
validator.isLength(password, { min: 8 }) &&
validator.matches(password, /[A-Z]/) &&
validator.matches(password, /[0-9]/);
if (!strong) {
errors.password = 'Weak password';
}
validator.isSlug('my-awesome-article');
validator.isHash(hash, 'md5');
validator.isHash(hash, 'sha256');
validator.isMimeType('application/json');
validator.isIP('192.168.0.1', 4);
validator.isIP('2001:db8::1', 6);
const schema = {
email: value =>
validator.isEmail(normalize(value)),
age: value =>
validator.isInt(normalize(value), {
min: 18
})
};
function validate(schema, data) {
const errors = {};
for (const field in schema) {
const valid = schema[field](data[field]);
if (!valid) {
errors[field] = 'Invalid value';
}
}
return errors;
}
Использование:
const errors = validate(schema, payload);
Validator.js отлично подходит для:
Но в крупных проектах часто требуются:
В таких случаях Validator.js обычно комбинируют с:
При этом Validator.js нередко используется внутри этих инструментов как низкоуровневый механизм проверки строковых значений.