Валидация данных — ключевой элемент при работе с пользовательским вводом, сетевыми запросами и формами. В контексте SvelteKit она выполняет сразу несколько задач:
Использование библиотеки Zod позволяет описывать схемы данных декларативно и переиспользовать их как на клиенте, так и на сервере.
Zod — это библиотека для декларативной валидации и парсинга данных с полной поддержкой TypeScript.
npm install zod
import { z } from 'zod';
const schema = z.string();
schema.parse('hello'); // OK
schema.parse(123); // Ошибка
Метод parse выбрасывает исключение при невалидных
данных.
Альтернатива — безопасная проверка:
const result = schema.safeParse(123);
if (!result.success) {
console.log(result.error);
}
SvelteKit разделяет код на клиентский и серверный. Zod удобно использовать в:
+page.server.ts — обработка форм+server.ts — API endpointsimport { z } from 'zod';
export const userSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
import { fail } from '@sveltejs/kit';
import { userSchema } from '$lib/schemas';
export const actions = {
default: async ({ request }) => {
const data = Object.fromEntries(await request.formData());
const result = userSchema.safeParse(data);
if (!result.success) {
return fail(400, {
errors: result.error.flatten().fieldErrors,
values: data
});
}
const validData = result.data;
return {
success: true
};
}
};
Zod предоставляет удобный API для извлечения ошибок.
result.error.flatten()
Возвращает:
{
fieldErrors: {
email: ['Invalid email'],
password: ['Too short']
}
}
<script>
export let form;
</script>
<input name="email" />
{#if form?.errors?.email}
<span>{form.errors.email[0]}</span>
{/if}
const schema = z.object({
user: z.object({
name: z.string(),
age: z.number()
})
});
z.array(z.string());
z.string().optional();
z.string().default('guest');
z.string().refine(val => val.includes('@'), {
message: 'Must contain @'
});
Позволяет проверять несколько полей одновременно:
z.object({
password: z.string(),
confirm: z.string()
}).superRefine((data, ctx) => {
if (data.password !== data.confirm) {
ctx.addIssue({
path: ['confirm'],
message: 'Passwords do not match',
code: z.ZodIssueCode.custom
});
}
});
Zod может не только валидировать, но и преобразовывать данные.
z.string().transform(val => val.trim());
z.string().transform(val => Number(val));
Одно из ключевых преимуществ Zod — автоматическое выведение типов.
const schema = z.object({
name: z.string(),
age: z.number()
});
type User = z.infer<typeof schema>;
Теперь User полностью соответствует схеме.
Рекомендуется хранить схемы в отдельной директории:
src/lib/schemas/
Пример:
// user.ts
export const userSchema = z.object({
email: z.string().email(),
password: z.string().min(6)
});
Иногда требуется разная строгость:
const baseSchema = z.object({
email: z.string().email()
});
export const clientSchema = baseSchema;
export const serverSchema = baseSchema.extend({
role: z.string()
});
Многие UI-библиотеки (например, формы) ожидают структуру ошибок. Zod хорошо подходит благодаря:
flatten() — удобный форматissues — подробная информацияZod поддерживает async-валидацию:
z.string().refine(async (val) => {
const exists = await checkUser(val);
return !exists;
}, {
message: 'User already exists'
});
Использование:
await schema.parseAsync(data);
const a = z.object({ a: z.string() });
const b = z.object({ b: z.number() });
const merged = a.merge(b);
const extended = a.extend({
c: z.boolean()
});
Полезно для сложных форм:
const schema = z.discriminatedUnion('type', [
z.object({ type: z.literal('a'), value: z.string() }),
z.object({ type: z.literal('b'), value: z.number() })
]);
В SvelteKit:
export const load = ({ url }) => {
const schema = z.object({
page: z.string().transform(Number)
});
const result = schema.safeParse({
page: url.searchParams.get('page')
});
if (!result.success) {
return { page: 1 };
}
return result.data;
};
FormData всегда содержит строки, поэтому часто требуется преобразование:
const schema = z.object({
age: z.string().transform(Number)
});
Или через preprocess:
z.preprocess(
val => Number(val),
z.number()
);
Рекомендуемый подход:
схемы — в lib/schemas
переиспользование в:
единый формат ошибок
Zod работает достаточно быстро, но при:
рекомендуется:
export function validate(schema, data) {
const result = schema.safeParse(data);
if (!result.success) {
return {
success: false,
errors: result.error.flatten().fieldErrors
};
}
return {
success: true,
data: result.data
};
}
Zod удобно использовать вместе с:
Это позволяет построить предсказуемую архитектуру:
1. Использование parse вместо safeParse Приводит к выбросу исключений.
2. Отсутствие трансформации FormData Все значения приходят строками.
3. Дублирование схем Нарушает DRY-принцип.
4. Смешивание клиентской и серверной логики Следует четко разделять зоны ответственности.
Можно создавать собственные утилиты:
const email = () => z.string().email();
const password = () => z.string().min(8);
Использование:
z.object({
email: email(),
password: password()
});
Грамотно выстроенная работа с Zod в SvelteKit выглядит так:
Это делает код более предсказуемым, масштабируемым и безопасным.