@IsISBN

@IsISBN — декоратор библиотеки Class-validator, предназначенный для проверки корректности значений ISBN (International Standard Book Number). Используется для валидации строк, представляющих книжные идентификаторы форматов ISBN-10 и ISBN-13, с поддержкой проверки контрольной цифры и допустимых символов.

ISBN существует в двух основных вариантах:

ISBN-10

Старый формат, состоящий из 10 символов. Последний символ может быть цифрой или символом X, который обозначает значение 10 в контрольной сумме.

Пример:

0306406152
0-306-40615-2
0 306 40615 2

ISBN-13

Современный формат, состоящий из 13 цифр. Начинается с префиксов 978 или 979.

Пример:

9780306406157
978-0-306-40615-7
978 0 306 40615 7

Декоратор поддерживает оба варианта при соответствующей конфигурации.

Синтаксис декоратора

@IsISBN(version?: number)

Параметры

  • version (необязательный): определяет допустимую версию ISBN

    • 10 — только ISBN-10
    • 13 — только ISBN-13
    • не указан — допускаются оба формата

Базовое использование

import { IsISBN } from 'class-validator';

export class BookDto {
  @IsISBN()
  isbn: string;
}

В данном случае допустимыми считаются как ISBN-10, так и ISBN-13.

Ограничение версии ISBN

Проверка только ISBN-10

import { IsISBN } from 'class-validator';

export class BookDto {
  @IsISBN(10)
  isbn: string;
}

Проверка только ISBN-13

import { IsISBN } from 'class-validator';

export class BookDto {
  @IsISBN(13)
  isbn: string;
}

При несоответствии версии значение считается невалидным, даже если формат строки корректен.

Правила валидации

Внутренняя логика проверки включает несколько этапов:

1. Очистка входных данных

Допускаются разделители:

  • дефис -
  • пробел

Они удаляются перед проверкой контрольной суммы.

2. Проверка структуры

  • ISBN-10: строго 10 символов после очистки
  • ISBN-13: строго 13 символов после очистки
  • допустимы только цифры (и X на последней позиции для ISBN-10)

3. Проверка контрольной суммы

ISBN-10

Используется взвешенная сумма:

(1×d1 + 2×d2 + ... + 10×d10) % 11 === 0

Если последний символ X, он интерпретируется как 10.

ISBN-13

Используется алгоритм с коэффициентами 1 и 3:

(d1 + 3×d2 + d3 + 3×d4 + ... ) % 10 === 0

Примеры невалидных значений

Неверная длина

123456789
978030640615

Ошибочная контрольная сумма

0-306-40615-3
978-0-306-40615-8

Недопустимые символы

978-0-306-40A15-7
ISBN9780306406157

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

import { IsISBN } from 'class-validator';

export class BookDto {
  @IsISBN(13, {
    message: 'ISBN должен соответствовать формату ISBN-13',
  })
  isbn: string;
}

Сообщение переопределяет стандартный текст ошибки, генерируемый валидатором.

Работа с трансформацией данных

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

export class BookDto {
  @IsISBN()
  isbn: string;
}
const dto = new BookDto();
dto.isbn = input.trim();

Для более сложных случаев используется явная очистка:

dto.isbn = input.replace(/[\s-]/g, '');

Использование с другими декораторами

Обязательное поле

import { IsNotEmpty, IsISBN } from 'class-validator';

export class BookDto {
  @IsNotEmpty()
  @IsISBN(13)
  isbn: string;
}

Проверка типа

import { IsString, IsISBN } from 'class-validator';

export class BookDto {
  @IsString()
  @IsISBN()
  isbn: string;
}

Порядок декораторов не влияет на результат валидации, но влияет на структуру ошибок.

Группы валидации

import { IsISBN } from 'class-validator';

export class BookDto {
  @IsISBN(13, { groups: ['create'] })
  isbn: string;
}
@Validate(BookDto, { groups: ['create'] })

Группы позволяют разделять сценарии, например создание и обновление сущности.

Условная валидация

В сочетании с ValidateIf:

import { ValidateIf, IsISBN } from 'class-validator';

export class BookDto {
  @ValidateIf(o => o.format === 'book')
  @IsISBN()
  isbn: string;

  format: string;
}

При несоответствии условия поле пропускается.

Особенности обработки ISBN-10 с символом X

Символ X допускается только на последней позиции:

class BookDto {
  @IsISBN(10)
  isbn: string;
}

Допустимо:

030640615X

Недопустимо:

X306406152

Частые причины ошибок

Наличие лишних символов

ISBN часто копируется с префиксами:

ISBN 978-0-306-40615-7

Такие строки требуют предварительной очистки.

Неверный формат разделителей

Смешивание пробелов и дефисов не всегда критично, но дополнительные символы ломают валидацию.

Использование старого ISBN-10 вместо ISBN-13

Некоторые источники предоставляют устаревший формат, который не проходит проверку при @IsISBN(13).

Поведение в NestJS

При использовании в DTO NestJS:

import { IsISBN } from 'class-validator';

export class CreateBookDto {
  @IsISBN(13)
  isbn: string;
}

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

app.useGlobalPipes(new ValidationPipe());

При ошибке возвращается стандартный HTTP-ответ с описанием нарушений.

Комбинирование с кастомными валидаторами

При необходимости расширенной логики:

import { registerDecorator, ValidationOptions } from 'class-validator';

export function IsValidBookISBN(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: 'isValidBookISBN',
      target: object.constructor,
      propertyName,
      options: validationOptions,
      validator: {
        validate(value: any) {
          return typeof value === 'string' && value.length > 0;
        },
      },
    });
  };
}

Поведение при null и undefined

Если не используются дополнительные декораторы:

  • undefined и null обычно пропускаются
  • для обязательной проверки требуется @IsNotEmpty() или @IsDefined()
@IsDefined()
@IsISBN()
isbn: string;

Совместимость

@IsISBN работает в средах:

  • Node.js
  • браузерных сборках (при корректной бандлизации)
  • TypeScript-проектах с reflect-metadata
  • NestJS-проектах

Основная зависимость — библиотека class-validator, использующая внутренние алгоритмы проверки ISBN без внешних API.