Обратная совместимость — способность библиотеки сохранять работоспособность существующего кода после обновления версии. Для библиотек валидации это особенно важно: изменение поведения валидаторов способно привести к отказу API, ошибкам регистрации пользователей, некорректной фильтрации данных и проблемам безопасности.
В экосистеме JavaScript библиотека Validator.js используется во множестве проектов:
Даже небольшое изменение логики проверки строк может затронуть тысячи строк кода.
Validator.js придерживается принципов SemVer:
MAJOR.MINOR.PATCH
Пример:
13.11.0
Расшифровка:
| Компонент | Значение |
|---|---|
| MAJOR | Ломающие изменения |
| MINOR | Новый функционал без поломки API |
| PATCH | Исправления ошибок |
Ломающими считаются изменения, при которых старый код начинает работать иначе или перестаёт работать вообще.
Примеры:
const validator = require('validator');
validator.isEmail('test@test');
В старых версиях некоторые некорректные email могли проходить проверку.
После обновления алгоритм стал строже:
validator.isEmail('test@test');
// false
Такое изменение повышает корректность валидации, но способно сломать старые формы регистрации.
Validator.js старается сохранять существующие методы даже после появления новых механизмов.
Например:
validator.isURL(url);
Метод продолжает работать многие версии подряд, несмотря на расширение внутренней логики.
Иногда API помечается как устаревший.
Признаки deprecated-функциональности:
Типичная схема поддержки совместимости:
validator.isLength(str, 5, 20);
validator.isLength(str, {
min: 5,
max: 20
});
Объект параметров:
Изменение порядка аргументов считается ломающим изменением.
validator.contains(str, seed);
validator.contains(seed, str);
Старый код начнёт работать неправильно без ошибок времени выполнения.
Некоторые изменения выглядят безопасно, но нарушают совместимость.
validator.isURL(url);
Допускались URL без протокола.
Теперь требуется http:// или https://.
validator.isURL('example.com');
// false
Чтобы уменьшить влияние обновлений, рекомендуется явно задавать параметры.
validator.isURL(url);
validator.isURL(url, {
require_protocol: false
});
Явная конфигурация снижает зависимость от будущих изменений поведения по умолчанию.
Validator.js часто используется внутри middleware.
app.post('/register', (req, res) => {
if (!validator.isEmail(req.body.email)) {
return res.status(400).send('Invalid email');
}
res.send('OK');
});
После обновления библиотеки часть email может перестать проходить проверку.
Главный механизм контроля совместимости — автоматические тесты.
describe('Email validation', () => {
test('must validate old emails', () => {
expect(
validator.isEmail('admin@example.com')
).toBe(true);
});
});
Иногда проверяется не только результат, но и структура ошибок.
expect(result).toMatchSnapshot();
После обновления Validator.js snapshot позволяет обнаружить изменение поведения.
Validator.js содержит функции очистки данных.
validator.escape('<script>');
Результат:
<script>
Изменение алгоритма экранирования способно повлиять:
Поддержка Unicode регулярно развивается.
Некоторые символы не распознавались:
validator.isAlpha('Привет');
После расширения локалей:
validator.isAlpha('Привет', 'ru-RU');
// true
Это улучшение функциональности, но иногда оно меняет старую бизнес-логику.
Validator.js поддерживает множество локалей:
validator.isAlpha(str, 'de-DE');
validator.isAlpha(str, 'fr-FR');
validator.isAlpha(str, 'ru-RU');
Добавление новых локалей обычно безопасно, но изменение существующих правил — потенциально ломающая операция.
Многие валидаторы основаны на regex.
validator.isMobilePhone(phone, 'ru-RU');
После обновления regex:
Версии Validator.js зависят от поддерживаемых версий Node.js.
Старая версия:
Node.js >= 10
Новая версия:
Node.js >= 18
Это типичный major-breaking change.
В package.json:
{
"engines": {
"node": ">=18"
}
}
Changelog — основной источник информации о совместимости.
Типичные разделы:
Нельзя обновлять Validator.js вслепую.
npm update
npm install validator@13.11.0
Для стабильности проекта часто фиксируется точная версия.
{
"dependencies": {
"validator": "13.11.0"
}
}
{
"dependencies": {
"validator": "^13.11.0"
}
}
Символ ^ допускает автоматические minor-обновления.
Даже minor-релизы иногда меняют поведение:
npm:
package-lock.json
Yarn:
yarn.lock
pnpm:
pnpm-lock.yaml
Lock-файлы фиксируют точные версии зависимостей.
Некоторые библиотеки используют Validator.js как peer dependency.
Пример:
{
"peerDependencies": {
"validator": "^13.0.0"
}
}
Нарушение диапазона версий может привести к конфликтам.
Библиотека Express Validator тесно связана с Validator.js.
body('email').isEmail()
Внутри используется Validator.js.
Изменение логики Validator.js автоматически влияет на middleware Express Validator.
Иногда создаются промежуточные обёртки.
function validateEmail(email) {
return validator.isEmail(email, {
allow_utf8_local_part: false
});
}
Преимущества:
Крупные проекты редко используют Validator.js напрямую.
Создаётся внутренний слой:
export class ValidationService {
static isEmail(email) {
return validator.isEmail(email);
}
}
Такой подход изолирует бизнес-логику от внешней библиотеки.
Контрактные тесты фиксируют ожидаемое поведение.
const validEmails = [
'admin@test.com',
'user@example.org'
];
for (const email of validEmails) {
expect(validator.isEmail(email)).toBe(true);
}
Особое внимание уделяется нестандартным данным.
validator.isEmail('');
validator.isEmail(null);
validator.isEmail(undefined);
validator.isEmail('a@a');
validator.isEmail('@@@');
Именно edge-case случаи чаще всего меняются между версиями.
Validator.js используется как в CommonJS, так и в ES Modules.
const validator = require('validator');
import validator from 'validator';
Изменение схемы экспорта — потенциально критическое breaking change.
Проблема возникает при одновременной поддержке:
Разные сборщики могут интерпретировать библиотеку по-разному.
Validator.js содержит TypeScript-типизацию.
validator.isEmail(email);
Изменение типов способно ломать проект даже без изменения runtime-поведения.
isEmail(str: string): boolean;
isEmail(str: unknown): boolean;
Либо наоборот — более строгие ограничения.
Системы CI автоматически проверяют совместимость.
steps:
- npm install
- npm test
После обновления Validator.js тесты сразу обнаружат проблемы.
Крупные системы обновляют зависимости постепенно.
Схема:
Иногда новая логика валидации включается флагами.
if (features.strictEmailValidation) {
return validator.isEmail(email);
}
Изменение правил валидации влияет на API.
Старый API принимал:
{
"phone": "12345"
}
После обновления Validator.js запрос начинает отклоняться.
Это может нарушить работу мобильных приложений и сторонних интеграций.
Иногда несовместимость вводится намеренно ради безопасности.
Более строгая проверка URL:
validator.isURL(url, {
protocols: ['https']
});
Старые небезопасные URL могут перестать проходить валидацию.
if (useNewValidation) {
return newValidator(data);
}
return oldValidator(data);
const oldResult = oldValidator(data);
const newResult = newValidator(data);
logDifference(oldResult, newResult);
Такой подход позволяет оценить влияние обновления до полного перехода.
Часто поверх Validator.js создаются собственные проверки.
function isCorporateEmail(email) {
return validator.isEmail(email)
&& email.endsWith('@company.com');
}
Изменение базового валидатора влияет и на пользовательскую логику.
Минимальный набор проверок:
import ValidationService from './services/validation.js';
export const emailOptions = {
allow_utf8_local_part: false,
require_tld: true
};
npm test
Перед каждым major-обновлением анализируются:
Текущая версия:
{
"validator": "13.7.0"
}
Изучение changelog версии 13.11.0.
Обновление:
npm install validator@13.11.0
Запуск тестов:
npm test
Проверка production-логов.
| Проблема | Последствие |
|---|---|
| Изменение regex | Неверная валидация |
| Новый Unicode | Изменение допустимых символов |
| Строгие URL-проверки | Ошибки API |
| Изменение типов TS | Ошибки компиляции |
| Удаление deprecated API | Runtime errors |
| Новый Node.js requirement | Невозможность запуска |
Надёжная интеграция Validator.js строится на нескольких принципах: