Перейти к основному содержанию
API поддерживает идемпотентность операций через заголовок Idempotency-Key. Это позволяет безопасно повторять запросы при сетевых сбоях или таймаутах, не создавая дублирующих операций.

Обязательные операции

Операции создания бронирований требуют обязательного заголовка Idempotency-Key:
  • POST /v2/booking/lounges — бронирование бизнес-зала
  • POST /v2/booking/fast-tracks — бронирование фаст-трека

Опциональные операции

Операции подтверждения и отмены бронирований идемпотентны по своей природе через бизнес-логику (повторный вызов возвращает 409 при недопустимом состоянии) и не требуют обязательного ключа идемпотентности. Однако рекомендуется передавать Idempotency-Key для упрощения идемпотентных ретраев при сетевых сбоях:
  • POST /v2/booking/lounges/{bookingID}/confirm — подтверждение брони бизнес-зала
  • POST /v2/booking/lounges/{bookingID}/cancel — отмена брони бизнес-зала
  • POST /v2/booking/fast-tracks/{bookingID}/confirm — подтверждение брони фаст-трека
  • POST /v2/booking/fast-tracks/{bookingID}/cancel — отмена брони фаст-трека

Формат ключа идемпотентности

Idempotency-Key — это строка длиной до 256 символов. Рекомендуется использовать UUID для обеспечения глобальной уникальности. Пример:
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

Поведение (Source-of-Truth)

При повторном запросе с тем же Idempotency-Key:

Совпадение тела запроса

Если тело запроса совпадает с сохранённым при первом использовании ключа:
  • Сервер возвращает строго тот же HTTP-код и тело ответа, что были возвращены при первом запросе
  • Заголовок Idempotency-Status: reused указывает на повторное использование результата
  • Операция не выполняется повторно

Несовпадение тела запроса

Если тело запроса отличается от сохранённого при первом использовании ключа:
  • Сервер возвращает 409 IdempotencyConflict
  • Операция не выполняется

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

Для определения конфликта сравниваются следующие поля:
  • POST /v2/booking/lounges: все поля LoungeBookingRequest:
    • lounge_id
    • first_name
    • last_name
    • email
    • phone
    • calling_code
    • transport_number
    • guests
  • POST /v2/booking/fast-tracks: все поля FastTrackBookingRequest:
    • fast_track_id
    • first_name
    • last_name
    • email
    • phone
    • calling_code
    • transport_number
    • guests
Сравнение выполняется путём нормализации JSON (игнорирование порядка полей, нормализация пробелов) и побайтового сравнения нормализованных представлений.

TTL и истечение срока действия

Ключ идемпотентности имеет TTL 72 часа с момента первого использования. После истечения TTL:
  • Ключ считается недействительным
  • Новый запрос с тем же ключом обрабатывается как новый запрос (создаётся новая операция)
  • Возвращается Idempotency-Status: created
  • Не возвращается ошибка 422 или 409

Заголовки ответа

Все операции, поддерживающие идемпотентность, возвращают:
  • Idempotency-Key: эхо переданного ключа
  • Idempotency-Status:
    • created — операция создана впервые
    • reused — операция повторно использована (возвращён сохранённый результат)

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

Успешное создание бронирования

Первый запрос:
POST /v2/booking/lounges HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "lounge_id": "123e4567-e89b-12d3-a456-426614174000",
  "first_name": "Ivan",
  "last_name": "Ivanov",
  "guests": [
    {
      "first_name": "Ivan",
      "last_name": "Ivanov",
      "type": "Adult",
      "lead": true
    }
  ]
}
Ответ:
HTTP/1.1 202 Accepted
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Idempotency-Status: created
Location: /v2/booking/lounges/789e4567-e89b-12d3-a456-426614174000

{
  "booking_id": "789e4567-e89b-12d3-a456-426614174000",
  "status": "Processing",
  "created_at": "2025-11-08T06:00:00Z"
}

Повторный запрос с тем же ключом и телом

Повторный запрос (идентичный первому):
POST /v2/booking/lounges HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "lounge_id": "123e4567-e89b-12d3-a456-426614174000",
  "first_name": "Ivan",
  "last_name": "Ivanov",
  "guests": [
    {
      "first_name": "Ivan",
      "last_name": "Ivanov",
      "type": "Adult",
      "lead": true
    }
  ]
}
Ответ (тот же, что и при первом запросе):
HTTP/1.1 202 Accepted
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Idempotency-Status: reused
Location: /v2/booking/lounges/789e4567-e89b-12d3-a456-426614174000

{
  "booking_id": "789e4567-e89b-12d3-a456-426614174000",
  "status": "Processing",
  "created_at": "2025-11-08T06:00:00Z"
}

Конфликт идемпотентности

Запрос с тем же ключом, но другим телом:
POST /v2/booking/lounges HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "lounge_id": "123e4567-e89b-12d3-a456-426614174000",
  "first_name": "Petr",  // Изменено имя
  "last_name": "Ivanov",
  "guests": [
    {
      "first_name": "Petr",
      "last_name": "Ivanov",
      "type": "Adult",
      "lead": true
    }
  ]
}
Ответ:
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "code": "IdempotencyConflict",
  "message": "Idempotency Key используется с другими параметрами",
  "request_id": "xxxx"
}

Рекомендации

  1. Генерация ключей: Используйте UUID v4 для генерации уникальных ключей идемпотентности
  2. Хранение ключей: Сохраняйте ключи идемпотентности вместе с результатами операций для возможности повторного использования
  3. Обработка ошибок: При получении 409 IdempotencyConflict проверьте, не изменились ли параметры запроса
  4. TTL: Учитывайте, что ключи действительны только 72 часа — после истечения срока используйте новый ключ