Опирается на правила: R-BATCH-1..5, R-ASYNC-1..4, R-LOC-1..3 и X-коды из REST API Style Guide → раздел Batch, async, локализация.

Важно знать

  • Batch обрабатывается поэлементно (partial success). Atomicity явно указывается.
  • POST /resources/batch или POST /resources/batch/<action>.
  • Request: { items: [...] }. Response: 200 + results + summary (success/failed counts).
  • Async через polling: 202 Accepted + Location + taskId + statusUrl.
  • Task statuses: PENDING / PROCESSING / COMPLETED / FAILED.
  • При COMPLETEDresultUrl обязателен. При FAILEDerror обязателен.
  • Локализация: Accept-Languagedetail, violations.message.
  • Не локализуются: code enum, title, type URI, имена JSON-полей.

Три темы для случаев, не покрытых стандартным CRUD: массовые операции, длительные задачи, multi-language. Каждая имеет своё стандартизованное решение, чтобы клиент знал чего ожидать.

Batch-операции

R-BATCH-1..5: partial success.

Endpoint

POST /api/v1/orders/batch                  ← batch для коллекции
POST /api/v1/notifications/batch/send      ← batch для action

Request

POST /api/v1/orders/batch
Content-Type: application/json

{
  "items": [
    { "productId": "aaa", "quantity": 2 },
    { "productId": "bbb", "quantity": 1 },
    { "productId": "ccc", "quantity": 5 }
  ]
}

Response — 200 + per-item results

HTTP/1.1 200 OK

{
  "results": [
    { "index": 0, "status": "SUCCESS", "orderId": "..." },
    { "index": 1, "status": "ERROR", "error": { "code": "INSUFFICIENT_STOCK", "detail": "Товар bbb отсутствует на складе" } },
    { "index": 2, "status": "SUCCESS", "orderId": "..." }
  ],
  "summary": {
    "total": 3,
    "succeeded": 2,
    "failed": 1
  }
}
  • 200 OK даже если часть элементов не прошла — это partial success, не failure всего batch.
  • index — позиция в исходном массиве (0-based).
  • statusSUCCESS или ERROR.
  • При ERROR — упрощённый объект error с code и detail, не полный ProblemDetails (т.к. ошибка относится к элементу, не к HTTP-запросу).
  • summary — агрегация (total, succeeded, failed).

Atomicity (all-or-nothing) — не дефолт. Если нужна — явно указывается в документации:

«Все элементы обрабатываются в одной транзакции; ошибка любого = откат всех. При partial failure — 400 с указанием failed индексов.»

Размер batch

R-BATCH-4..5:

  • Максимум указан в OpenAPI/документации (например, 100).
  • Превышение → 400 + code: BATCH_SIZE_EXCEEDED.
{
  "type": "urn:problem:order-service:batch-size-exceeded",
  "status": 400,
  "title": "Bad Request",
  "detail": "Размер batch превышает максимум (100 элементов)",
  "code": "BATCH_SIZE_EXCEEDED"
}

Async-операции

R-ASYNC-1..4: 202 Accepted + polling.

Для операций, которые не могут завершиться за время HTTP-запроса (генерация отчёта 30s, обработка batch 5min).

Submit — 202 Accepted

POST /api/v1/reports/generate
Content-Type: application/json

{ "dateFrom": "2026-01-01", "dateTo": "2026-12-31" }

HTTP/1.1 202 Accepted
Location: /api/v1/tasks/550e8400-...

{
  "taskId": "550e8400-...",
  "status": "PENDING",
  "createdAt": "2026-05-26T10:30:00Z",
  "statusUrl": "/api/v1/tasks/550e8400-..."
}
  • 202 Accepted — запрос принят, обработка асинхронная.
  • Location — URL для опроса задачи.
  • taskId — идентификатор задачи.
  • statusUrl — то же что Location, но в body (для клиентов, которые не читают headers).

Polling — GET /tasks/{id}

В процессе:

{
  "taskId": "550e8400-...",
  "status": "PROCESSING",
  "progress": 45,
  "createdAt": "2026-05-26T10:30:00Z"
}

Завершено:

{
  "taskId": "550e8400-...",
  "status": "COMPLETED",
  "progress": 100,
  "createdAt": "2026-05-26T10:30:00Z",
  "completedAt": "2026-05-26T10:35:00Z",
  "resultUrl": "/api/v1/reports/550e8400-..."
}

Ошибка:

{
  "taskId": "550e8400-...",
  "status": "FAILED",
  "createdAt": "2026-05-26T10:30:00Z",
  "completedAt": "2026-05-26T10:32:00Z",
  "error": {
    "code": "REPORT_GENERATION_FAILED",
    "detail": "Не удалось сформировать отчет: данные за период отсутствуют"
  }
}

Статусы задачи

R-ASYNC-3..4:

StatusЧто
PENDINGсоздана, ожидает обработки
PROCESSINGвыполняется
COMPLETEDзавершена, resultUrl обязателен
FAILEDзавершена с ошибкой, error обязателен

Polling-period — клиент выбирает (обычно 1-5 секунд для коротких задач, 30-60 для длинных). Сервер может вернуть Retry-After header с рекомендацией.

Альтернатива polling — WebSocket / Server-Sent Events для real-time. UCP дефолт — polling (simpler, stateless).

Локализация

R-LOC-1..3: через Accept-Language.

Request

GET /api/v1/orders/{id}
Accept-Language: ru

GET /api/v1/orders/{id}
Accept-Language: en

Accept-Language отсутствует → server использует язык по умолчанию для проекта (обычно ru для UCP).

Что локализуется

  • detail в ProblemDetails — для пользователя.
  • message в violations — для отображения рядом с полем.
// Accept-Language: ru
{
  "code": "ORDER_NOT_FOUND",
  "detail": "Заказ не найден"
}

// Accept-Language: en
{
  "code": "ORDER_NOT_FOUND",
  "detail": "Order not found"
}

Что НЕ локализуется

R-LOC-X1:

  • code — всегда английский (ORDER_EMPTY, не ЗАКАЗ_ПУСТОЙ).
  • title — стандартное название HTTP-статуса на английском (Bad Request, Not Found).
  • type — URI/URN, английский.
  • Имена JSON-полейorderId, не идЗаказа.
// ✗ — локализация code
{ "code": "ЗАКАЗ_ПУСТОЙ" }

// ✓
{ "code": "ORDER_EMPTY" }

Логика: enum-коды используются клиентским кодом (switch (error.code)) — не должны зависеть от user language.

Что запрещено

АнтипаттернПравилоЧто взамен
Batch atomicity по умолчаниюR-BATCH-3partial success + явная декларация если atomicity нужна
Batch 4xx на partial failureR-BATCH-3200 + per-item status
Batch без summaryR-BATCH-3total/succeeded/failed
Batch без max-sizeR-BATCH-4явное ограничение
Async без Location headerR-ASYNC-1обязателен
Async COMPLETED без resultUrlR-ASYNC-4обязателен
Async FAILED без errorR-ASYNC-4обязателен
Polling без status-machine документацииR-ASYNC-3явные допустимые статусы
code: ЗАКАЗ_ПУСТОЙ (русский enum)R-LOC-X1английский
title локализованR-LOC-X1стандартное название HTTP
JSON-поля локализованыR-LOC-X1английский
Accept-Language ignoredR-LOC-1использовать или default

Куда дальше

  • REST API → Batch, async, локализация (нормативно) — формулировки.
  • Ошибки RFC 9457 — code, detail, title, type правила.
  • Заголовки и трассировка — Idempotency-Key для batch, Location для async.
  • Rate limiting, файлы, deprecation — long-running как альтернатива.
  • Resilience → async polling — task-queue реализация на backend.
  • JSON и формат ответов — content + pagination.