@IsLatitude, @IsLongitude

Валидация географических координат в прикладных JavaScript и TypeScript-приложениях опирается на строгие математические диапазоны значений. Широта и долгота представляют собой числовые величины, которые должны соответствовать геодезическим ограничениям: широта варьируется в диапазоне от -90 до 90, долгота — от -180 до 180. Нарушение этих границ делает координаты некорректными и потенциально опасными для дальнейшей обработки в геоинформационных системах, API карт и сервисах маршрутизации.

В библиотеке class-validator предусмотрены специализированные декораторы для проверки таких значений: @IsLatitude и @IsLongitude. Они обеспечивают строгую проверку числовых полей без необходимости ручной реализации диапазонной логики.


@IsLatitude

Декоратор @IsLatitude применяется к числовым полям, содержащим значение широты. Проверка основана на математическом диапазоне допустимых значений:

  • минимальное значение: -90
  • максимальное значение: 90

Любое значение, выходящее за пределы этого интервала, считается невалидным.

Поведение валидации

Проверка включает несколько уровней:

  • контроль типа значения (ожидается число или строка, приводимая к числу)
  • проверка диапазона
  • отклонение NaN и бесконечных значений

Внутри class-validator используется строгая логика сравнения, исключающая пограничные ошибки при обработке входных данных из HTTP-запросов.

Пример использования

import { IsLatitude } from 'class-validator';

export class LocationDto {
  @IsLatitude()
  lat: number;
}

В этом случае любое значение вне диапазона [-90, 90] приведёт к ошибке валидации.

Работа со строковыми значениями

При использовании совместно с class-transformer возможно преобразование входных данных:

import { Type } from 'class-transformer';
import { IsLatitude } from 'class-validator';

export class LocationDto {
  @Type(() => Number)
  @IsLatitude()
  lat: number;
}

Это позволяет корректно обрабатывать значения, поступающие из HTTP payload в виде строк.

Сообщения об ошибках

По умолчанию формируется стандартное сообщение, однако возможно переопределение:

import { IsLatitude } from 'class-validator';

export class LocationDto {
  @IsLatitude({ message: 'Недопустимое значение широты' })
  lat: number;
}

@IsLongitude

Декоратор @IsLongitude предназначен для проверки долготы. Допустимый диапазон значений:

  • от -180 до 180

Логика проверки аналогична @IsLatitude, но с другим числовым интервалом.

Основные особенности

  • строгая проверка диапазона
  • исключение некорректных чисел (NaN, Infinity)
  • поддержка строковых значений при трансформации

Пример DTO

import { IsLongitude } from 'class-validator';

export class LocationDto {
  @IsLongitude()
  lng: number;
}

Комбинация с трансформацией типов

import { Type } from 'class-transformer';
import { IsLongitude } from 'class-validator';

export class LocationDto {
  @Type(() => Number)
  @IsLongitude()
  lng: number;
}

Совместное использование @IsLatitude и @IsLongitude

Чаще всего координаты используются в паре, формируя географическую точку. В таких случаях оба декоратора применяются одновременно в одном DTO.

import { IsLatitude, IsLongitude } from 'class-validator';
import { Type } from 'class-transformer';

export class CoordinatesDto {
  @Type(() => Number)
  @IsLatitude()
  lat: number;

  @Type(() => Number)
  @IsLongitude()
  lng: number;
}

Такое представление обеспечивает целостность данных на уровне модели.


Особенности обработки входных данных

В реальных приложениях координаты часто приходят:

  • из query-параметров URL
  • из JSON тела запроса
  • из внешних API

На уровне HTTP данные нередко представлены строками, что требует дополнительного преобразования типов. Без использования class-transformer возможны ложные срабатывания или пропуск ошибок.

Типичный сценарий некорректных данных:

  • "91" для широты
  • "200" для долготы
  • "NaN"
  • пустые строки

Декораторы @IsLatitude и @IsLongitude обеспечивают единообразную обработку подобных случаев при корректной конфигурации трансформации.


Интеграция с NestJS ValidationPipe

В экосистеме NestJS валидация координат часто выполняется автоматически через ValidationPipe.

import { ValidationPipe } from '@nestjs/common';

app.useGlobalPipes(
  new ValidationPipe({
    transform: true,
    whitelist: true,
  }),
);

При такой конфигурации:

  • входные данные автоматически преобразуются в DTO
  • применяются декораторы class-validator
  • некорректные координаты блокируются до попадания в бизнес-логику

Диапазонная природа валидации

Географические координаты являются примером ограниченных числовых доменов. В отличие от произвольных чисел, здесь критически важна геометрическая корректность:

  • широта ограничена сферой вращения Земли
  • долгота представляет собой угловое смещение относительно нулевого меридиана

Декораторы реализуют эти ограничения как чистую проверку диапазона без геопространственных преобразований.


Пограничные значения

Особое внимание требуется при работе с граничными значениями:

  • -90 и 90 считаются валидными значениями широты
  • -180 и 180 считаются валидными значениями долготы

Примеры корректных случаев:

lat = 90      // Северный полюс
lat = -90     // Южный полюс
lng = 180     // линия смены даты
lng = -180    // та же линия в противоположной записи

Поведение при некорректных типах

Если значение не может быть интерпретировано как число, валидация завершается ошибкой:

  • null
  • undefined
  • пустые строки (без трансформации)
  • объекты

При этом важно учитывать порядок применения декораторов: трансформация должна выполняться до валидации.


Кастомизация логики сообщений

class-validator позволяет задавать контекстные сообщения, что особенно полезно при построении API:

@IsLatitude({ message: 'Широта должна находиться в диапазоне от -90 до 90 градусов' })
lat: number;
@IsLongitude({ message: 'Долгота должна находиться в диапазоне от -180 до 180 градусов' })
lng: number;

Использование в сложных структурах данных

Координаты часто являются частью более сложных моделей:

import { IsLatitude, IsLongitude } from 'class-validator';
import { Type } from 'class-transformer';

class GeoPointDto {
  @Type(() => Number)
  @IsLatitude()
  latitude: number;

  @Type(() => Number)
  @IsLongitude()
  longitude: number;
}

class PlaceDto {
  name: string;

  location: GeoPointDto;
}

При такой структуре валидируется не только примитивное значение, но и вложенный объект координат.


Типичные ошибки при использовании

Распространённые проблемы при работе с декораторами координат:

  • отсутствие трансформации типов (строки вместо чисел)
  • попытка хранения координат в формате массива без DTO-структуры
  • игнорирование границ диапазона на уровне фронтенда
  • смешивание широты и долготы местами

Поведение в массивных структурах

При использовании массивов координат применяется дополнительная настройка:

import { ValidateNested, IsLatitude, IsLongitude } from 'class-validator';
import { Type } from 'class-transformer';

class PointDto {
  @IsLatitude()
  lat: number;

  @IsLongitude()
  lng: number;
}

class RouteDto {
  @ValidateNested({ each: true })
  @Type(() => PointDto)
  points: PointDto[];
}

Каждый элемент массива проходит независимую валидацию.


Ограничения и модель проверки

@IsLatitude и @IsLongitude не выполняют:

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

Они ограничиваются исключительно проверкой диапазона чисел, оставляя геодезическую интерпретацию на уровне прикладной логики или специализированных библиотек.