IP-адреса и доменные имена

При работе с сетевыми приложениями на JavaScript часто требуется проверка корректности IP-адресов и доменных имён. Эти данные используются при настройке API, работе с прокси, конфигурации серверов, логировании и системах маршрутизации. Ошибки на этом уровне приводят к трудноуловимым сбоям, поэтому строгая валидация становится обязательной частью прикладной логики.

Библиотека Zod предоставляет декларативный способ описания схем данных, включая специализированные валидаторы для строковых значений, таких как IP-адреса и URL-подобные структуры.


Валидация IP-адресов

IP-адреса бывают двух основных типов:

  • IPv4 — классический формат из четырёх октетов
  • IPv6 — расширенный формат, поддерживающий более сложные сетевые конфигурации

IPv4

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

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

Проверка доменных имён через refine

В отличие от 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"); // ошибка

Разбор структуры домена

Доменные имена состоят из уровней:

  • TLD (Top-Level Domain).com, .org, .net
  • SLD (Second-Level Domain)example в example.com
  • поддоменыapi.example.com

Корректная валидация должна учитывать:

  • отсутствие запрещённых символов
  • отсутствие дефисов в начале и конце сегментов
  • допустимую длину (до 253 символов в полном имени)
  • корректные зоны доменов

Более строгая проверка

Для продакшн-сценариев часто требуется более точная проверка:

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 и домена

Во многих системах требуется принимать либо 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");

Такой подход особенно полезен для:

  • конфигурации серверов
  • настройки прокси
  • описания endpoints
  • систем мониторинга

Валидация URL как альтернатива

Если требуется более широкий контекст, включающий протокол и путь, используется встроенная проверка 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();

Типизация в TypeScript

Одно из ключевых преимуществ Zod — автоматическая генерация типов.

const ipSchema = z.string().ip();

type IPAddress = z.infer<typeof ipSchema>;

Результат:

  • IPAddress будет строкой, прошедшей проверку IP-формата
  • исключаются ошибки на уровне компиляции

Типичные ошибки при валидации

Использование только regex для IP

Регулярные выражения часто не учитывают:

  • диапазон 0–255
  • ведущие нули
  • IPv6-сокращения

Zod решает эти проблемы встроенными алгоритмами.


Перепутанные уровни домена

Некорректные проверки часто допускают:

  • example..com
  • -example.com
  • example-.com

Без поуровневой проверки такие ошибки остаются незамеченными.


Практическая структура схем

В реальных проектах удобно централизовать схемы:

export const networkSchema = {
  ipv4: z.string().ip({ version: "v4" }),
  ipv6: z.string().ip({ version: "v6" }),
  ip: z.string().ip(),
  domain: strictDomainSchema,
  host: hostSchema
};

Такой подход упрощает:

  • переиспользование
  • тестирование
  • поддержку кода
  • единообразие API-валидации