Работа с файлами в веб-приложениях требует строгого контроля входящих данных, поскольку загрузка бинарного контента затрагивает безопасность, производительность и целостность системы. Библиотека Zod предоставляет единый подход к описанию и проверке структур данных, включая файлы, поступающие через формы, API или потоковые загрузки.
В браузерной среде файл представлен объектом File,
который наследуется от Blob. Валидация таких объектов в Zod
начинается с проверки типа экземпляра:
import { z } from "zod";
const fileSchema = z.instanceof(File);
Подобная схема гарантирует, что значение действительно является файлом, а не строкой, числом или произвольным объектом.
В серверной среде (например, Node.js) файлы часто представлены через
библиотеки загрузки, такие как multer, где структура отличается. В таких
случаях применяется более гибкая проверка через z.any() с
последующей валидацией структуры вручную либо через
z.object().
Одним из ключевых параметров является ограничение по размеру. В Zod
для этого используется метод refine, позволяющий добавлять
пользовательские правила:
const fileWithSizeSchema = z.instanceof(File).refine(
(file) => file.size <= 5 * 1024 * 1024,
{
message: "Размер файла превышает 5MB"
}
);
Здесь логика проверки отделена от структуры, что сохраняет декларативность схемы.
Контроль типа содержимого важен для предотвращения загрузки
нежелательных форматов. MIME-тип доступен через
file.type:
const imageFileSchema = z.instanceof(File).refine(
(file) => ["image/jpeg", "image/png", "image/webp"].includes(file.type),
{
message: "Поддерживаются только изображения JPEG, PNG и WEBP"
}
);
Подобная схема часто используется для аватаров, документов и медиафайлов.
В реальных сценариях требуется одновременно проверять несколько
характеристик: тип, размер и имя файла. Zod позволяет объединять условия
через последовательные вызовы refine:
const uploadSchema = z.instanceof(File)
.refine(file => file.size <= 10 * 1024 * 1024, {
message: "Файл слишком большой"
})
.refine(file => file.type === "application/pdf", {
message: "Допустим только PDF"
})
.refine(file => file.name.endsWith(".pdf"), {
message: "Некорректное расширение файла"
});
Такой подход сохраняет читаемость схемы и позволяет расширять правила без изменения структуры.
При множественной загрузке данные поступают в виде массива файлов.
Zod предоставляет композицию схем через array:
const multipleFilesSchema = z.array(
z.instanceof(File).refine(file => file.size <= 2 * 1024 * 1024, {
message: "Каждый файл должен быть не более 2MB"
})
);
Валидация применяется к каждому элементу массива независимо, обеспечивая единообразные ограничения.
Иногда требуется не только проверка, но и преобразование структуры
файла в более удобный формат. В таких случаях используется
transform:
const normalizedFileSchema = z.instanceof(File).transform((file) => ({
name: file.name,
size: file.size,
type: file.type
}));
Результатом становится нормализованный объект, пригодный для хранения или передачи в API.
Загрузки через HTTP часто приходят в виде FormData. Zod
не парсит его напрямую, но может валидировать извлечённые значения:
const formSchema = z.object({
file: z.instanceof(File),
description: z.string().min(1)
});
После извлечения данных из FormData структура передаётся
в safeParse:
const data = {
file: formData.get("file"),
description: formData.get("description")
};
const result = formSchema.safeParse(data);
Такой подход позволяет централизовать контроль входных данных.
Zod поддерживает детализированные сообщения об ошибках, что особенно важно при работе с файлами:
const schema = z.instanceof(File).refine(
(file) => file.size > 0,
{
message: "Пустой файл недопустим",
path: ["file"]
}
);
Поле path позволяет точно указать источник ошибки внутри
структуры данных.
В сложных формах требования к файлу могут зависеть от других полей:
const schema = z.object({
type: z.enum(["avatar", "document"]),
file: z.instanceof(File)
}).refine((data) => {
if (data.type === "avatar") {
return data.file.size <= 1 * 1024 * 1024;
}
return true;
}, {
message: "Аватар не должен превышать 1MB"
});
Подобная логика позволяет связывать бизнес-правила с файловыми ограничениями.
Некоторые проверки требуют обращения к внешним сервисам, например анализ содержимого файла. Zod поддерживает асинхронные схемы:
const asyncSchema = z.instanceof(File).refine(async (file) => {
const buffer = await file.arrayBuffer();
return buffer.byteLength > 100;
});
Такая модель применяется при антивирусной проверке, анализе изображений или чтении метаданных.
Метод safeParse используется для предотвращения
исключений при невалидных данных:
const result = fileSchema.safeParse(input);
if (!result.success) {
console.log(result.error.format());
}
Структурированные ошибки позволяют точно определить причину отказа валидации.
Работа с файлами в Zod зависит от окружения. В браузере доступен
полноценный объект File, тогда как в Node.js требуется
адаптация входных данных. В серверных приложениях часто используется
промежуточный слой, приводящий данные к единому виду перед применением
схем.
Особое внимание требуется уделять сериализации: объекты
File не преобразуются напрямую в JSON, поэтому для передачи
данных между слоями используется трансформация или извлечение
метаданных.
При работе с потоками данных файлы могут поступать частями. В таких случаях Zod используется для проверки итоговой структуры после сборки:
const chunkedSchema = z.object({
filename: z.string(),
chunks: z.array(z.instanceof(Uint8Array)),
totalSize: z.number()
});
Проверка гарантирует целостность собранного файла перед сохранением.