Интеграция библиотеки Validator.js с базами данных решает сразу несколько критически важных задач:
Даже если база данных уже содержит ограничения (UNIQUE,
NOT NULL, CHECK, типы колонок), прикладная
валидация остаётся обязательной. Validator.js выполняет предварительную
проверку ещё до обращения к БД.
Типичный поток обработки выглядит следующим образом:
HTTP Request
↓
Парсинг данных
↓
Validator.js
↓
ORM / Query Builder
↓
База данных
Validator.js должен работать до выполнения SQL-запросов.
Пример:
import validator fr om 'validator'
function validateUser(data) {
if (!validator.isEmail(data.email)) {
throw new Error('Некорректный email')
}
if (!validator.isLength(data.password, { min: 8 })) {
throw new Error('Слишком короткий пароль')
}
}
import validator fr om 'validator'
import db fr om './db.js'
async function createUser(email) {
if (!validator.isEmail(email)) {
throw new Error('Некорректный email')
}
await db.query(
'INS ERT INTO users(email) VALUES($1)',
[email]
)
}
Здесь Validator.js:
Validator.js содержит функции sanitization.
import validator fr om 'validator'
const email = validator.normalizeEmail(
' USER@GMAIL.COM '
)
console.log(email)
Результат:
user@gmail.com
Часто используется комбинация:
const email = validator.normalizeEmail(
validator.trim(inputEmail)
)
import pg fr om 'pg'
import validator fr om 'validator'
const { Pool } = pg
const pool = new Pool({
user: 'postgres',
password: '123456',
database: 'app'
})
async function registerUser(data) {
if (!validator.isEmail(data.email)) {
throw new Error('Неверный email')
}
if (!validator.isStrongPassword(data.password)) {
throw new Error('Слабый пароль')
}
const query = `
INS ERT INTO users(email, password)
VALUES($1, $2)
`
await pool.query(query, [
validator.normalizeEmail(data.email),
data.password
])
}
PostgreSQL активно использует UUID.
if (!validator.isUUID(userId)) {
throw new Error('Некорректный UUID')
}
Можно указать конкретную версию:
validator.isUUID(userId, 4)
PostgreSQL поддерживает JSON и JSONB.
const metadata = '{"theme":"dark"}'
if (!validator.isJSON(metadata)) {
throw new Error('Некорректный JSON')
}
if (!validator.isInt(age + '', {
min: 0,
max: 120
})) {
throw new Error('Некорректный возраст')
}
if (!validator.isDecimal(price + '')) {
throw new Error('Некорректная цена')
}
if (!validator.isDate(birthDate)) {
throw new Error('Некорректная дата')
}
Validator.js не содержит встроенной проверки MongoDB ObjectId, однако можно использовать регулярное выражение.
import validator from 'validator'
function isObjectId(id) {
return validator.matches(
id,
/^[0-9a-fA-F]{24}$/
)
}
MongoDB часто используется для хранения документов с URL.
if (!validator.isURL(website)) {
throw new Error('Некорректный URL')
}
Sequelize поддерживает встроенные валидаторы на основе Validator.js.
import { DataTypes } from 'sequelize'
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
validate: {
isEmail: true
}
},
username: {
type: DataTypes.STRING,
validate: {
isAlphanumeric: true,
len: [3, 20]
}
}
})
Sequelize внутри использует Validator.js.
const User = sequelize.define('User', {
password: {
type: DataTypes.STRING,
validate: {
strong(val ue) {
if (!validator.isStrongPassword(value)) {
throw new Error('Слабый пароль')
}
}
}
}
})
Mongoose позволяет подключать Validator.js вручную.
import mongoose from 'mongoose'
import validator from 'validator'
const UserSchema = new mongoose.Schema({
email: {
type: String,
validate(value) {
return validator.isEmail(value)
}
}
})
const ArticleSchema = new mongoose.Schema({
image: {
type: String,
validate(value) {
return validator.isURL(value)
}
}
})
Prisma не включает встроенную интеграцию с Validator.js, поэтому валидация обычно выполняется отдельно.
import validator from 'validator'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function createPost(data) {
if (!validator.isSlug(data.slug)) {
throw new Error('Некорректный slug')
}
return prisma.post.create({
data
})
}
Validator.js содержит функции очистки строк.
const name = validator.trim(input)
Удаляет пробелы по краям.
const text = validator.escape(comment)
Преобразует HTML-символы:
<script>
в:
<script>
Удаление управляющих символов:
validator.stripLow(text)
Validator.js не заменяет параметризованные запросы.
Неправильно:
const sql = `
SEL ECT * FROM users
WH ERE email = '${email}'
`
Правильно:
await db.query(
'SELE CT * FR OM users WH ERE email = $1',
[email]
)
Validator.js используется как дополнительный уровень защиты.
Validator.js не умеет проверять уникальность напрямую, поскольку это задача базы данных.
Обычно используется комбинация:
Пример:
if (!validator.isEmail(email)) {
throw new Error('Некорректный email')
}
const exists = await db.query(
'SEL ECT id FR OM users WH ERE email = $1',
[email]
)
if (exists.rows.length > 0) {
throw new Error('Email уже существует')
}
Валидация выполняется до открытия транзакции.
if (!validator.isCurrency(amount + '')) {
throw new Error('Некорректная сумма')
}
const client = await pool.connect()
try {
await client.query('BEGIN')
// SQL-запросы
await client.query('COMMIT')
}
catch (err) {
await client.query('ROLLBACK')
}
function validateUsers(users) {
return users.every(user => {
return validator.isEmail(user.email)
})
}
function validateUser(user) {
const errors = []
if (!validator.isEmail(user.email)) {
errors.push('Некорректный email')
}
if (!validator.isMobilePhone(user.phone, 'any')) {
errors.push('Некорректный телефон')
}
return errors
}
Express часто используется вместе с Validator.js.
import validator fr om 'validator'
export function validateUser(req, res, next) {
const { email } = req.body
if (!validator.isEmail(email)) {
return res.status(400).json({
error: 'Некорректный email'
})
}
next()
}
async function updateUser(id, data) {
if (data.email) {
if (!validator.isEmail(data.email)) {
throw new Error('Некорректный email')
}
}
if (data.website) {
if (!validator.isURL(data.website)) {
throw new Error('Некорректный URL')
}
}
}
if (!validator.isInt(lim it + '', {
min: 1,
max: 100
})) {
throw new Error('Некорректный lim it')
}
const allowed = ['name', 'created_at']
if (!allowed.includes(sort)) {
throw new Error('Недопустимое поле сортировки')
}
Validator.js синхронен, но легко комбинируется с асинхронными проверками.
async function validate(data) {
if (!validator.isEmail(data.email)) {
throw new Error('Некорректный email')
}
const user = await db.query(
'SEL ECT id FR OM users WH ERE email = $1',
[data.email]
)
if (user.rows.length > 0) {
throw new Error('Email занят')
}
}
// validators/user.js
import validator from 'validator'
export function validateEmail(email) {
return validator.isEmail(email)
}
export function validatePassword(password) {
return validator.isStrongPassword(password)
}
import {
validateEmail,
validatePassword
} from './validators/user.js'
class CreateUserDTO {
constructor(data) {
this.email = data.email
this.password = data.password
}
validate() {
const errors = []
if (!validator.isEmail(this.email)) {
errors.push('Неверный email')
}
if (!validator.isStrongPassword(this.password)) {
errors.push('Слабый пароль')
}
return errors
}
}
Validator.js работает быстро, однако при массовой обработке данных следует:
Неправильно:
validator.isEmail(email)
Правильно:
validator.isEmail(
validator.trim(email)
)
Неправильно:
await saveToDB(data)
validate(data)
Frontend-валидация не заменяет backend-проверки.
Validator.js часто используется совместно с библиотеками схемной валидации.
Joi:
const schema = Joi.object({
email: Joi.string().email()
})
Zod:
const schema = z.object({
email: z.string().email()
})
Validator.js при этом может использоваться для дополнительной проверки и sanitization.
src/
├── validators/
│ ├── user.js
│ ├── post.js
│ └── common.js
│
├── services/
├── repositories/
├── database/
└── routes/
Особенно важно проверять:
import validator from 'validator'
async function createUser(data) {
const errors = []
const email = validator.normalizeEmail(
validator.trim(data.email)
)
if (!validator.isEmail(email)) {
errors.push('Некорректный email')
}
if (!validator.isStrongPassword(data.password)) {
errors.push('Слабый пароль')
}
if (!validator.isMobilePhone(
data.phone,
'any'
)) {
errors.push('Некорректный телефон')
}
if (errors.length > 0) {
throw new Error(errors.join(', '))
}
await db.query(
`
INS ERT IN TO users(
email,
password,
phone
)
VALUES($1, $2, $3)
`,
[
email,
data.password,
data.phone
]
)
}