Проверка данных формы
Валидация — проверка данных до того, как их сохранить. Посетитель может отправить пустой заголовок, слишком длинный текст или вообще не то поле. Сервер обязан проверить всё сам: проверки в браузере легко обойти.
Ручная проверка
Самый простой вариант — несколько условий в обработчике store из прошлого урока:
// src/controllers/postsController.js
export function store(req, res) {
const title = String(req.body.title ?? '').trim();
const body = String(req.body.body ?? '').trim();
const errors = [];
if (title.length < 3) {
errors.push('Заголовок — не короче 3 символов');
}
if (body === '') {
errors.push('Напишите текст статьи');
}
if (errors.length > 0) {
return res.status(422).render('posts/new', {
title: 'Новая статья',
errors,
values: { title, body },
});
}
const post = { id: posts.length + 1, title, body };
posts.push(post);
res.redirect(`/posts/${post.id}`);
}При ошибке форма показывается снова с кодом 422 — «данные не прошли проверку». Перенаправлять здесь не нужно: посетитель должен увидеть свои введённые значения.
Ошибки в шаблоне
Добавьте в views/posts/new.ejs вывод ошибок и верните введённые значения в поля:
<% if (locals.errors) { %>
<ul class="errors">
<% for (const error of errors) { %>
<li><%= error %></li>
<% } %>
</ul>
<% } %>
<form method="post" action="/posts">
<input name="title" value="<%= locals.values?.title ?? '' %>">
<textarea name="body"><%= locals.values?.body ?? '' %></textarea>
<button>Опубликовать</button>
</form>locals — объект со всеми данными шаблона. Через него можно проверить переменную, которую не передали: при первом показе формы errors нет, и без locals. шаблон упал бы с ошибкой.
Проверка через Zod
Когда полей много, условия разрастаются. Библиотека Zod описывает правила одной схемой:
npm install zodСоздайте файл src/validation/postSchema.js:
// src/validation/postSchema.js
import { z } from 'zod';
export const postSchema = z.object({
title: z.string().trim().min(3, 'Заголовок — не короче 3 символов').max(120, 'Заголовок — не длиннее 120 символов'),
body: z.string().trim().min(1, 'Напишите текст статьи'),
});Метод safeParse() не выбрасывает исключение, а возвращает результат с полем success:
// src/controllers/postsController.js
import { postSchema } from '../validation/postSchema.js';
export function store(req, res) {
const result = postSchema.safeParse(req.body);
if (!result.success) {
return res.status(422).render('posts/new', {
title: 'Новая статья',
errors: result.error.issues.map((issue) => issue.message),
values: req.body,
});
}
const post = { id: posts.length + 1, ...result.data };
posts.push(post);
res.redirect(`/posts/${post.id}`);
}Отправьте форму с заголовком «Hi» — над формой появится «Заголовок — не короче 3 символов». В result.data лежат уже очищенные значения: без пробелов по краям и только с описанными в схеме полями.
Частая ошибка
Атрибуты required и minlength в HTML удобны, но это только подсказка браузеру. Запрос можно отправить через curl или изменить форму в инструментах разработчика. Оставляйте их для удобства посетителя, но всегда повторяйте проверку на сервере.