При работе с сетевыми приложениями на JavaScript часто требуется проверка корректности IP-адресов и доменных имён. Эти данные используются при настройке API, работе с прокси, конфигурации серверов, логировании и системах маршрутизации. Ошибки на этом уровне приводят к трудноуловимым сбоям, поэтому строгая валидация становится обязательной частью прикладной логики.
Библиотека Zod предоставляет декларативный способ описания схем данных, включая специализированные валидаторы для строковых значений, таких как IP-адреса и URL-подобные структуры.
IP-адреса бывают двух основных типов:
IPv4 состоит из четырёх чисел от 0 до 255, разделённых точками:
192.168.0.1
8.8.8.8
127.0.0.1
В Zod встроенная поддержка позволяет валидировать такие значения без регулярных выражений:
import { z } from "zod";
const ipv4Schema = z.string().ip({ version: "v4" });
ipv4Schema.parse("192.168.0.1"); // валидно
ipv4Schema.parse("999.999.999.999"); // ошибка
Использование параметра version позволяет строго
ограничить формат, исключая IPv6-адреса и некорректные строки.
IPv6 представляет собой более длинную запись, содержащую шестнадцатеричные блоки:
2001:0db8:85a3:0000:0000:8a2e:0370:7334
::1
fe80::1ff:fe23:4567:890a
Валидация:
const ipv6Schema = z.string().ip({ version: "v6" });
ipv6Schema.parse("::1"); // валидно
ipv6Schema.parse("192.168.0.1"); // ошибка
В реальных приложениях часто требуется принимать оба типа IP-адресов:
const ipSchema = z.string().ip();
ipSchema.parse("192.168.1.1");
ipSchema.parse("2001:db8::1");
Без указания версии Zod допускает как IPv4, так и IPv6, что удобно для универсальных API.
Доменные имена используются для идентификации ресурсов в сети и являются человекочитаемой альтернативой IP-адресам.
Примеры:
example.com
sub.domain.org
api.service.io
В отличие от IP-адресов, в Zod нет отдельного встроенного метода
domain(), поэтому используется комбинированный подход с
refine или регулярными выражениями.
const domainSchema = z.string().refine((value) => {
const domainRegex =
/^(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.[A-Za-z]{2,})+$/;
return domainRegex.test(value);
}, {
message: "Некорректное доменное имя"
});
domainSchema.parse("example.com"); // валидно
domainSchema.parse("-invalid.domain"); // ошибка
Доменные имена состоят из уровней:
.com,
.org, .netexample в
example.comapi.example.comКорректная валидация должна учитывать:
Для продакшн-сценариев часто требуется более точная проверка:
const strictDomainSchema = z.string().refine((value) => {
if (value.length > 253) return false;
const labels = value.split(".");
const labelRegex = /^[a-zA-Z0-9-]{1,63}$/;
return labels.every((label) => {
return (
labelRegex.test(label) &&
!label.startsWith("-") &&
!label.endsWith("-")
);
});
}, {
message: "Некорректный формат доменного имени"
});
Во многих системах требуется принимать либо IP-адрес, либо домен.
const hostSchema = z.union([
z.string().ip(),
z.string().refine((value) => {
const domainRegex =
/^(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.[A-Za-z]{2,})+$/;
return domainRegex.test(value);
})
]);
hostSchema.parse("192.168.0.1");
hostSchema.parse("example.com");
Такой подход особенно полезен для:
Если требуется более широкий контекст, включающий протокол и путь, используется встроенная проверка URL:
const urlSchema = z.string().url();
urlSchema.parse("https://example.com");
Однако URL не заменяет проверку IP и домена, поскольку:
http, https)Zod позволяет не только валидировать, но и преобразовывать данные.
const normalizedDomain = z
.string()
.transform((val) => val.toLowerCase())
.pipe(strictDomainSchema);
const trimmedIp = z.string().transform((val) => val.trim()).ip();
Одно из ключевых преимуществ Zod — автоматическая генерация типов.
const ipSchema = z.string().ip();
type IPAddress = z.infer<typeof ipSchema>;
Результат:
IPAddress будет строкой, прошедшей проверку
IP-форматаРегулярные выражения часто не учитывают:
Zod решает эти проблемы встроенными алгоритмами.
Некорректные проверки часто допускают:
example..com-example.comexample-.comБез поуровневой проверки такие ошибки остаются незамеченными.
В реальных проектах удобно централизовать схемы:
export const networkSchema = {
ipv4: z.string().ip({ version: "v4" }),
ipv6: z.string().ip({ version: "v6" }),
ip: z.string().ip(),
domain: strictDomainSchema,
host: hostSchema
};
Такой подход упрощает: