Input Validation — zod, joi bilan so'rovni tekshirish
Muammodan boshlaylik
Foydalanuvchi ro'yxatdan o'tish formini to'ldirdi. Siz hech narsa tekshirmasdan saqladingiz:
app.post('/register', async (req, res) => {
const { name, email, age } = req.body;
await pool.query('INSERT INTO users (name, email, age) VALUES ($1, $2, $3)', [name, email, age]);
res.status(201).json({ message: 'Yaratildi' });
});
Kimdir quyidagini yuborsa:
{ "name": "", "email": "bu-email-emas", "age": -999 }
Bo'sh nom, noto'g'ri email, manfiy yosh — barchasi ma'lumotlar bazasiga saqlanadi. Keyinchalik bu ma'lumotlar bilan ishlash qiyin, foydalanuvchiga noto'g'ri ma'lumot ko'rsatiladi.
Validation — foydalanuvchidan kelgan ma'lumotni qabul qilishdan oldin tekshirish.
Zod nima?
Zod — TypeScript va JavaScript uchun schema validation kutubxonasi. Siz "ma'lumot qanday ko'rinishi kerak" ni tasvirlaysiz — Zod tekshiradi.
Joi ham mashhur alternativa. Ikkalasi o'xshash, lekin Zod TypeScript bilan yaxshiroq ishlaydi va zamonaviyroq. Yangi loyihalarda Zod tavsiya etiladi.
npm install zod
Schema yaratish
const { z } = require('zod');
const registerSchema = z.object({
name: z.string().min(2, 'Ism kamida 2 ta harf').max(50),
email: z.string().email('Email noto\'g\'ri formatda'),
age: z.number().int().min(18, 'Yosh kamida 18').max(120).optional(),
role: z.enum(['user', 'admin']).default('user'),
});
Schema — "bu ob'ekt qanday bo'lishi kerak" degan tavsif. Har bir maydon uchun tur va qoidalar belgilanadi.
Validation middleware
Schema ni route da to'g'ridan-to'g'ri ishlatish o'rniga — middleware yaratish yaxshiroq. Bir marta yoziladi, istalgan route da ishlatiladi:
function validate(schema) {
return (req, res, next) => {
const result = schema.safeParse(req.body);
if (!result.success) {
const errors = result.error.errors.map(e => ({
field: e.path.join('.'),
message: e.message,
}));
return res.status(400).json({ errors });
}
req.body = result.data; // tozalangan va default qiymatlar bilan
next();
};
}
safeParse — xato chiqarmaydi, natijani { success, data, error } sifatida qaytaradi. parse esa xato chiqaradi — try/catch kerak.
req.body = result.data — muhim. Zod ma'lumotni tozalaydi: ortiqcha maydonlarni o'chiradi, default qiymatlarni qo'shadi, turlarni to'g'rilaydi.
Route da ishlatish
const registerSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
password: z.string().min(8, 'Parol kamida 8 ta belgi'),
});
router.post('/register', validate(registerSchema), async (req, res, next) => {
try {
// req.body allaqachon tekshirilgan va tozalangan
const { name, email, password } = req.body;
// ...
} catch (err) {
next(err);
}
});
Validation muvaffaqiyatsiz bo'lsa — handler chaqirilmaydi. Foydalanuvchi xato xabar oladi:
{
"errors": [
{ "field": "email", "message": "Invalid email" },
{ "field": "password", "message": "Parol kamida 8 ta belgi" }
]
}
Params va query validation
Body dan tashqari params va query ham tekshirilishi kerak:
function validateParams(schema) {
return (req, res, next) => {
const result = schema.safeParse(req.params);
if (!result.success) return res.status(400).json({ message: 'Noto\'g\'ri parametr' });
req.params = result.data;
next();
};
}
const idSchema = z.object({
id: z.string().regex(/^\d+$/, 'ID raqam bo\'lishi kerak').transform(Number),
});
router.get('/users/:id', validateParams(idSchema), async (req, res, next) => {
const id = req.params.id; // endi number
// ...
});
transform(Number) — string ni raqamga aylantiradi. Params har doim string keladi — bu bilan avtomatik konvertatsiya.
Joi — alternativa
Joi ham keng tarqalgan. Sintaksis biroz boshqacha:
const Joi = require('joi');
const registerSchema = Joi.object({
name: Joi.string().min(2).max(50).required(),
email: Joi.string().email().required(),
password: Joi.string().min(8).required(),
age: Joi.number().integer().min(18).max(120),
});
// Tekshirish:
const { error, value } = registerSchema.validate(req.body, { abortEarly: false });
if (error) {
return res.status(400).json({
errors: error.details.map(d => ({ field: d.path[0], message: d.message }))
});
}
abortEarly: false — birinchi xatoda to'xtamaslik, barcha xatolarni topish.
Tez-tez uchraydigan xatolar
Validation ni faqat frontendda qilish:
// Frontend tekshirdi — backend tekshirmaydi
// Hacker frontendni o'tkazib, to'g'ridan-to'g'ri API ga yuboradi
Validation har doim backend da ham bo'lishi kerak. Frontend validation — foydalanuvchi qulayligi uchun. Backend validation — xavfsizlik uchun.
req.body = result.data unutish:
const result = schema.safeParse(req.body);
if (!result.success) return res.status(400).json(...);
// req.body = result.data; — unutildi
// req.body da hali eski, tozalanmagan ma'lumot
Xulosa
Validation — foydalanuvchidan kelgan ma'lumotni qabul qilishdan oldin tekshirish. Zod — zamonaviy, TypeScript bilan yaxshi. Joi — eski, lekin keng tarqalgan.
Middleware sifatida yoziladi — bir marta, istalgan route da ishlatiladi. req.body = result.data — tozalangan ma'lumot.
Frontend validation — qulaylik uchun. Backend validation — xavfsizlik uchun. Ikkalasi kerak.
Keyingi dars
30-dars: SQL Injection, XSS, CSRF — qanday himoyalanish