Опирается на правила:
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.
- При COMPLETED —
resultUrlобязателен. При FAILED —errorобязателен.- Локализация:
Accept-Language→detail,violations.message.- Не локализуются:
codeenum,title,typeURI, имена 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).status—SUCCESSили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-3 | partial success + явная декларация если atomicity нужна |
| Batch 4xx на partial failure | R-BATCH-3 | 200 + per-item status |
Batch без summary | R-BATCH-3 | total/succeeded/failed |
| Batch без max-size | R-BATCH-4 | явное ограничение |
Async без Location header | R-ASYNC-1 | обязателен |
Async COMPLETED без resultUrl | R-ASYNC-4 | обязателен |
Async FAILED без error | R-ASYNC-4 | обязателен |
| Polling без status-machine документации | R-ASYNC-3 | явные допустимые статусы |
code: ЗАКАЗ_ПУСТОЙ (русский enum) | R-LOC-X1 | английский |
title локализован | R-LOC-X1 | стандартное название HTTP |
| JSON-поля локализованы | R-LOC-X1 | английский |
Accept-Language ignored | R-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.