Fastify схемы

В основе подхода Fastify лежит декларативное описание контрактов между клиентом и сервером. Эти контракты выражаются через схемы, основанные на спецификации JSON Schema, и обеспечиваются высокопроизводительным валидатором Ajv. Такая архитектура позволяет объединить в одном месте валидацию входящих данных, сериализацию ответов и документацию API.

Схема в Fastify — это объект, описывающий структуру данных для различных частей HTTP-запроса и ответа:

  • body — тело запроса
  • querystring — параметры строки запроса
  • params — параметры маршрута
  • headers — заголовки
  • response — структура ответа

Каждая из этих секций может быть независимо валидирована и оптимизирована.


Базовая структура схемы маршрута

Схема в контексте маршрута задаётся через поле schema:

fastify.route({
  method: 'POST',
  url: '/user/:id',
  schema: {
    params: {
      type: 'object',
      properties: {
        id: { type: 'string' }
      },
      required: ['id']
    },
    body: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        age: { type: 'integer', minimum: 0 }
      },
      required: ['name']
    },
    response: {
      200: {
        type: 'object',
        properties: {
          ok: { type: 'boolean' }
        }
      }
    }
  },
  handler: async (request, reply) => {
    return { ok: true }
  }
})

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


Роль Ajv в Fastify

Ajv используется как основной движок валидации JSON Schema. Fastify не интерпретирует схемы во время запроса — вместо этого он:

  1. Компилирует схему при регистрации маршрута
  2. Преобразует её в оптимизированную функцию
  3. Выполняет эту функцию на каждый запрос

Такой подход исключает накладные расходы на парсинг и интерпретацию схемы в рантайме.

Ключевые возможности Ajv, используемые Fastify:

  • строгая валидация типов
  • поддержка ссылок $ref
  • компоновка схем
  • кастомные форматы
  • расширения через keywords

Компиляция схем и производительность

Fastify делает ставку на минимизацию overhead. Каждая схема проходит этап компиляции:

  • JSON Schema преобразуется в JS-функцию
  • устраняются повторяющиеся проверки
  • оптимизируются условия ветвления
  • кешируются валидаторы

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


Валидация body, params, querystring и headers

Body

Используется для проверки структуры входящего JSON:

body: {
  type: 'object',
  required: ['email'],
  properties: {
    email: { type: 'string', format: 'email' }
  }
}

Params

Используется для параметров URL:

params: {
  type: 'object',
  properties: {
    id: { type: 'number' }
  }
}

Querystring

Часто требует преобразования типов:

querystring: {
  type: 'object',
  properties: {
    page: { type: 'integer', default: 1 },
    limit: { type: 'integer', maximum: 100 }
  }
}

Headers

Особенность headers — нормализация ключей:

headers: {
  type: 'object',
  properties: {
    'x-api-key': { type: 'string' }
  },
  required: ['x-api-key']
}

Схемы ответа и контракт API

Секция response определяет структуру данных, которые сервер гарантированно возвращает.

response: {
  200: {
    type: 'object',
    properties: {
      data: { type: 'array' }
    }
  }
}

Fastify использует эту схему не только для валидации, но и для сериализации ответа. Это означает:

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

Повторное использование схем и $id

Для масштабных приложений критично переиспользование схем. Ajv поддерживает идентификаторы $id:

const userSchema = {
  $id: 'userSchema',
  type: 'object',
  properties: {
    id: { type: 'string' }
  }
}

Далее схема может использоваться через $ref:

body: {
  $ref: 'userSchema'
}

Fastify автоматически регистрирует и резолвит такие зависимости через внутренний реестр Ajv.


Строгий режим и контроль схем

Fastify включает строгую проверку схем, которая предотвращает:

  • неизвестные типы
  • некорректные ключи
  • неоднозначные конструкции JSON Schema

Это снижает вероятность ошибок на этапе разработки, но требует более дисциплинированного описания контрактов.


Кастомные форматы и расширения Ajv

Ajv позволяет расширять систему типов через форматы:

fastify.addSchema({
  $id: 'customEmail',
  type: 'string',
  format: 'email'
})

Или через runtime-регистрацию:

fastify.addHook('onRoute', (routeOptions) => {
  // расширение логики схем
})

Также поддерживаются custom keywords, позволяющие внедрять бизнес-логику прямо в схему.


Преобразование данных (coercion)

Fastify может автоматически приводить типы:

querystring: {
  type: 'object',
  properties: {
    page: { type: 'integer' }
  }
}

Запрос ?page=1 будет преобразован из строки в число при включённой опции coerceTypes.


Обработка дополнительных полей

Ajv и Fastify поддерживают стратегию работы с лишними полями:

  • removeAdditional: true — удаляет лишние поля
  • removeAdditional: 'all' — более строгая очистка
  • additionalProperties: false — запрещает любые неописанные поля

Это важно для контроля контрактов и защиты API от «грязных» входных данных.


Ошибки валидации и их структура

При нарушении схемы Fastify возвращает структурированную ошибку:

  • путь до поля (instancePath)
  • причина (message)
  • тип ошибки (keyword)

Это позволяет точно локализовать проблему без ручного парсинга запроса.


Влияние схем на архитектуру приложения

Использование схем в Fastify приводит к формированию контрактно-ориентированной архитектуры:

  • API становится самодокументируемым
  • бизнес-логика отделяется от валидации
  • уменьшается количество runtime-ошибок
  • повышается стабильность интеграций

Схемы начинают играть роль центрального описания доменной модели на уровне HTTP-интерфейса.


Схемы и генерация документации

На основе схем можно автоматически строить OpenAPI-описание. Fastify использует их как источник истины для:

  • генерации Swagger UI
  • описания моделей данных
  • документирования эндпоинтов

Это устраняет необходимость дублирования контрактов в коде и документации.


Особенности поведения при вложенных схемах

Глубоко вложенные объекты и массивы обрабатываются через рекурсивные проверки Ajv. При этом:

  • каждая ветка схемы компилируется один раз
  • ссылки $ref заменяются на прямые вызовы
  • структура становится плоской на уровне исполнения

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


Типичные архитектурные ошибки при работе со схемами

Часто встречающиеся проблемы:

  • избыточная вложенность объектов без необходимости
  • дублирование схем вместо $ref
  • отсутствие required, приводящее к неявным ошибкам
  • использование слишком широких типов (object без ограничений)
  • смешивание бизнес-логики и схем валидации

Такие ошибки приводят к потере преимуществ декларативного подхода и усложняют поддержку API.