JTD (JSON Type Definition)

Модель JTD и её назначение

JSON Type Definition представляет собой стандарт описания структуры JSON-данных, ориентированный на простоту и строгую типизацию. В отличие от JSON Schema, JTD делает акцент на минимальном наборе конструкций, достаточном для описания типов данных, исключая сложные логические выражения и избыточные механизмы валидации.

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

Ключевая особенность JTD заключается в том, что схема описывает не набор ограничений, а тип данных, что делает её ближе к моделям типов в языках программирования.


Основные принципы JTD

Строгая типизация

JTD работает с фиксированным набором типов:

  • boolean
  • string
  • float32 / float64
  • int8, uint8, int16, uint16, int32
  • timestamp
  • enum
  • properties
  • optionalProperties
  • values
  • elements
  • discriminator

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


Отсутствие логических операторов

В JTD отсутствуют конструкции:

  • oneOf
  • anyOf
  • allOf
  • not

Это упрощает валидацию и делает схемы более предсказуемыми. Вместо композиции логики используется строгая структура объектов.


Подключение поддержки JTD в Ajv

Ajv требует явного включения поддержки JTD-режима через дополнительные пакеты или конфигурацию.

import Ajv from "ajv/dist/jtd";

const ajv = new Ajv();

В этом режиме компилятор схем работает исключительно с JTD-структурами, игнорируя JSON Schema.


Базовые типы JTD в Ajv

Строки

const schema = {
  type: "string"
};

const validate = ajv.compile(schema);

validate("text");   // true
validate(123);      // false

Целые числа и числа с плавающей точкой

const schemaInt = {
  type: "int32"
};

const schemaFloat = {
  type: "float64"
};

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


Булев тип

const schema = {
  type: "boolean"
};

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


Объекты в JTD

properties — обязательные поля

const schema = {
  properties: {
    id: { type: "string" },
    age: { type: "uint8" }
  }
};

Особенность properties заключается в том, что все указанные поля являются обязательными.


optionalProperties — необязательные поля

const schema = {
  properties: {
    id: { type: "string" }
  },
  optionalProperties: {
    nickname: { type: "string" }
  }
};

Если nickname отсутствует в объекте, валидация не проваливается.


additionalProperties отсутствуют по умолчанию

JTD не допускает произвольных полей, если они не описаны явно.

const schema = {
  properties: {
    id: { type: "string" }
  }
};

Объекты с дополнительными полями считаются невалидными.


Массивы

elements

const schema = {
  elements: {
    type: "string"
  }
};

Описывает массив строк.

Пример:

validate(["a", "b", "c"]); // true
validate([1, 2, 3]);       // false

Перечисления (enum)

Строгие фиксированные значения

const schema = {
  enum: ["admin", "user", "guest"]
};

Любое значение вне списка считается невалидным.


Вложенные структуры

Комбинация объектов и массивов

const schema = {
  properties: {
    user: {
      properties: {
        id: { type: "string" },
        roles: {
          elements: {
            enum: ["admin", "editor", "viewer"]
          }
        }
      }
    }
  }
};

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


Дискриминатор (discriminator)

Полиморфные структуры

JTD поддерживает дискриминатор для выбора структуры объекта по значению поля.

const schema = {
  discriminator: "type",
  mapping: {
    admin: {
      properties: {
        type: { type: "string" },
        permissions: {
          elements: { type: "string" }
        }
      }
    },
    user: {
      properties: {
        type: { type: "string" },
        email: { type: "string" }
      }
    }
  }
};

Принцип работы дискриминатора

Поле type определяет, какая схема применяется к объекту. Это заменяет сложные конструкции условной логики.

validate({
  type: "admin",
  permissions: ["read", "write"]
}); // true

Валидация данных

Компиляция схемы

Ajv компилирует JTD-схему в оптимизированную функцию:

const validate = ajv.compile(schema);

Результат проверки

const valid = validate(data);

При ошибке:

validate.errors;

Ошибки содержат информацию о несоответствии типов или структуры.


Отличия JTD от JSON Schema в Ajv

Простота модели

JTD:

  • только типы и структуры
  • отсутствует логическая алгебра схем
  • нет сложных выражений

JSON Schema:

  • богатая система ограничений
  • поддержка условий и комбинирования
  • более высокая сложность

Производительность

JTD в Ajv компилируется в более простые функции, что снижает накладные расходы при валидации.


Ограниченность выразительности

JTD не позволяет:

  • проверять диапазоны чисел через minimum/maximum
  • использовать регулярные выражения в схеме
  • задавать сложные зависимости между полями

Типизация и генерация моделей

JTD часто используется как источник для генерации TypeScript-типов.

Пример соответствия:

const schema = {
  properties: {
    id: { type: "string" },
    active: { type: "boolean" }
  }
};

Эквивалент TypeScript:

type Model = {
  id: string;
  active: boolean;
};

Практика использования в Ajv

Централизованная схема данных

JTD часто применяется для описания API-контрактов:

const userSchema = {
  properties: {
    id: { type: "string" },
    email: { type: "string" },
    age: { type: "uint8" }
  },
  optionalProperties: {
    nickname: { type: "string" }
  }
};

Проверка входных данных API

const validateUser = ajv.compile(userSchema);

if (!validateUser(request.body)) {
  throw new Error("Invalid payload");
}

Ограничения JTD в контексте Ajv

JTD не предназначен для сложной бизнес-валидации. Его использование эффективно в случаях, когда:

  • требуется строгая структура данных
  • важна высокая скорость проверки
  • необходимо минимизировать сложность схем

При необходимости расширенной логики предпочтение отдается JSON Schema.


Оптимизация схем JTD

Минимизация вложенности

Глубокие структуры снижают читаемость и увеличивают сложность сопровождения.

Явное описание всех полей

Отсутствие additionalProperties требует строгого контроля модели данных.

Использование discriminator вместо условных схем

Полиморфизм через discriminator предпочтительнее вложенных проверок типов.