GH GambleHub

API коды ошибок и best practices

1) Зачем стандартизировать ошибки

Предсказуемость для клиентов: единый формат и поведение ретраев.
Ускорение дебага: `trace_id`/`request_id`, стабильные `error_code`.
Безопасность: не утекут SQL/stack traces/конфиги.
Наблюдаемость: отчетность по таксономии ошибок (валидация, квоты, таймауты и т. д.).

2) Базовые принципы

1. Единый формат ответа для всех 4xx/5xx (и для 2xx с частичными ошибками — отдельная схема).
2. Четкая семантика HTTP: верный статус важнее всего.
3. Два уровня кода: транспортный (`status`) и доменный стабильный `error_code`.
4. Retriable vs Non-retriable: указывайте явно и давайте подсказку по бэк-оффу.
5. Безопасность по умолчанию: подробности — только клиенту с правами; без внутренних трасс.
6. Локализация: машинный код остается стабильным, текст — переводим.

3) Единый формат ошибки (на базе RFC 7807)

Рекомендуемый JSON (расширенный `application/problem+json`):
json
{
"type": "https://api. example. com/errors/validation_failed",
"title": "Validation failed",
"status": 422,
"error_code": "VAL_001",
"detail": "Field 'email' must be a valid address",
"instance": "req_01HZY...93",
"trace_id": "a1b2c3d4e5f6",
"retriable": false,
"errors": [
{"field": "email", "code": "email_invalid", "message": "Invalid email"}
],
"hint": "Fix payload and retry",
"meta": {"docs": "https://docs. example. com/errors#VAL_001"}
}

Обязательные: `type`, `title`, `status`, `error_code`, `trace_id`.
Опционально: `errors[]` (по полям), `retriable`, `hint`, `meta`.

Заголовки в ответе:
  • `Content-Type: application/problem+json`
  • `X-Request-ID`/`Traceparent` (W3C)
  • (для 429/503) `Retry-After` (секунды или дата)

4) Семантика HTTP статусов (слияние «классики» и практики)

2xx (успех с нюансами)

200 OK — обычный успех.
201 Created — создан ресурс (Location).
202 Accepted — асинхронно в очереди (дайте `status_url`).
207 Multi-Status — частичный успех (избегайте, если можно).

4xx (ошибка клиента)

400 Bad Request — синтаксис/формат, но не валидация полей (лучше 422).
401 Unauthorized — нет/неверный токен. Давайте `WWW-Authenticate`.
403 Forbidden — токен валиден, но прав не хватает (RBAC/ABAC/лимиты).
404 Not Found — ресурс/эндпоинт отсутствует.
409 Conflict — конфликт версий/состояния (optimistic locking, idempotency).
410 Gone — эндпоинт навсегда убран.
412 Precondition Failed — ETag/If-Match не прошел.
415 Unsupported Media Type — неправильный `Content-Type`.
422 Unprocessable Entity — валидация бизнес-правил.
429 Too Many Requests — превышены квоты/скорость (см. §7).

5xx (ошибка сервера)

500 Internal Server Error — внезапная ошибка; не разглашать детали.
502 Bad Gateway — ошибка апстрима.
503 Service Unavailable — деградация/перегруз, дайте `Retry-After`.
504 Gateway Timeout — таймаут бэкенда.

💡 Порог: 4xx не ретраим, 5xx можно ретраить (с backoff/jitter), 429 — ретрай после `Retry-After`.

5) Таксономия доменных `error_code`

Рекомендуем диапазоны:
  • `AUTH_` — аутентификация/авторизация.
  • `VAL_` — валидация входных данных.
  • `RATELIMIT_` — квоты и скорость.
  • `IDEMP_` — идемпотентность/дубликаты.
  • `CONFLICT_` — версии/состояние.
  • `DEP_` — зависимости (PSP/DNS/SMTP).
  • `PAY_` — бизнес-ошибки платежного домена.
  • `SEC_` — безопасность (подписи, HMAC, mTLS).
  • `INT_` — внутренние внезапные.
Требования:
  • Стабильность во времени (back-compat).
  • Описания и примеры в каталоге ошибок (docs + machine-readable JSON).

6) Retriable vs Non-retriable

Поля:
  • `retriable: true|false`
  • Если `true` — обязательно `Retry-After` (в секундах) или контракт «экспоненциальный бэк-офф (начиная с 1–2 с, макс 30–60 с)».

Retriable обычно: `502/503/504`, некоторые `500`, `429` (после окна).
Non-retriable: `400/401/403/404/409/410/415/422`.

7) Rate limit & quota ошибки (429)

Тело:
json
{
"type": "https://api. example. com/errors/rate_limited",
"title": "Rate limit exceeded",
"status": 429,
"error_code": "RATELIMIT_RPS",
"detail": "Too many requests",
"retriable": true
}
Заголовки:
  • `Retry-After: 12`
  • `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`
  • Для квот: `X-Quota-Limit`, `X-Quota-Remaining`, `X-Quota-Reset`

8) Идемпотентность и конфликты

В запросах на запись — `Idempotency-Key` (уникален в пределах 24–72 ч).
Конфликт повторной операции → 409 Conflict с `error_code: "IDEMP_REPLAY"`.
Конфликт версий ресурса по ETag → 412 Precondition Failed.
В ответе приложите `resource_id`/`status_url` для безопасного повторного запроса.

9) Валидация и 422

Возвращайте список ошибок по полям:
json
{
"status": 422,
"error_code": "VAL_001",
"errors": [
{"field":"email","code":"email_invalid","message":"Invalid email"},
{"field":"age","code":"min","message":"Must be >= 18"}
]
}
Правила:
  • Не дублируйте то же в 400 — 422 предпочтительнее для бизнес-валидации.
  • Сообщения — человекочитаемые; `code` — машинный.

10) Безопасность ошибок

Никогда: stack traces, SQL, пути файлов, приватные имена хостов.
Редактируйте PII; следите за GDPR/DSAR.
Для подписи/HMAC: различайте `SEC_SIGNATURE_MISMATCH` (403) и `SEC_TIMESTAMP_SKEW` (401/403) с подсказкой «проверьте время ±5 мин».

11) Корреляция и наблюдаемость

Всегда добавляйте `trace_id`/`X-Request-ID` и прокидывайте в логи/трассы.
Ошибки агрегируйте по `error_code` и `status` → дашборды «топ-ошибки», «new vs known».
Алерты: всплеск 5xx/422/429, латентность p95, share of errors.

12) gRPC/GraphQL/Webhooks — маппинги

gRPC ↔ HTTP

gRPCЗначениеHTTP
`OK`успех200
`INVALID_ARGUMENT`валидация422/400
`UNAUTHENTICATED`нет токена401
`PERMISSION_DENIED`нет прав403
`NOT_FOUND`нет ресурса404
`ALREADY_EXISTS`конфликт409
`FAILED_PRECONDITION`ETag/предусловия412
`RESOURCE_EXHAUSTED`квоты429
`UNAVAILABLE`недоступно503
`DEADLINE_EXCEEDED`таймаут504
`INTERNAL`внутренняя500

GraphQL

Транспорт 200, но `errors[]` внутри — добавляйте `extensions.code` и `trace_id`.
Для «фатала» (аутентификация/квоты) — лучше реальный HTTP 401/403/429.

Webhooks

Считайте успешным только 2xx получателя.
Ретраи с экспоненциальным бэк-оффом, `X-Webhook-ID`, `X-Signature`.
410 от получателя — остановить ретраи (endpoint удален).

13) Версионирование ошибок

`type`/`error_code` — стабильные; новые — только добавлять.
При изменении схемы тела — повышайте минорную версию API или `problem+json; v=2`.
Документация: таблица кодов + примеры; changelog ошибок.

14) Документация (OpenAPI фрагменты)

Глобальные ответы

yaml components:
responses:
Problem:
description: Problem Details content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
schemas:
Problem:
type: object required: [type, title, status, error_code, trace_id]
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
error_code: { type: string }
detail: { type: string }
instance: { type: string }
trace_id: { type: string }
retriable: { type: boolean }
errors:
type: array items:
type: object properties:
field: { type: string }
code: { type: string }
message: { type: string }

Пример эндпоинта

yaml paths:
/v1/users:
post:
responses:
'201': { description: Created }
'401': { $ref: '#/components/responses/Problem' }
'422': { $ref: '#/components/responses/Problem' }
'429': { $ref: '#/components/responses/Problem' }
'500': { $ref: '#/components/responses/Problem' }

15) Тестирование и качество

Контракт-тесты: соответствие `application/problem+json`, обязательные поля.
Negative tests: все ветви 401/403/404/409/422/429/500.
Chaos/latency: проверка ретраев на 5xx/503/504/429 (`Retry-After`).
Security tests: отсутствие внутренних сообщений, корректная маска PII.
Backward-compat: старые клиенты понимают новые поля (добавляйте, не ломайте).

16) Чек-лист внедрения

  • Единый `problem+json` + стабильные `error_code`.
  • Корректная семантика HTTP/гRPC/GraphQL.
  • Retriable/non-retriable + `Retry-After`/рекомендации бэк-оффа.
  • Rate-limit заголовки и 429 поведение.
  • Идемпотентность (`Idempotency-Key`, 409/412).
  • Безопасность: без stack traces/секретов, PII-редакция.
  • `trace_id`/`X-Request-ID` во всех ошибках.
  • Документация каталога ошибок и примеры.
  • Мониторинг по таксономии ошибок.
  • Автотесты негативных сценариев.

17) Мини-FAQ

Чем 400 отличается от 422?
400 — сломанный запрос (синтаксис/тип содержимого). 422 — валидный по синтаксису, но бизнес-правила не прошли.

Когда 401, а когда 403?
401 — нет/неверный токен; 403 — токен есть, прав не хватает.

Нужен ли всегда `Retry-After`?
Для 429/503 — да; для остальных retriable — желательно давать явную рекомендацию.

Итог

Хорошо спроектированные ошибки — это контракт: корректный HTTP-статус, единый `problem+json`, стабильные `error_code`, явные подсказки по ретраям и строгая безопасность. Стандартизируйте формат, документируйте таксономию, добавьте телеметрию и тесты — и ваш API станет предсказуемым, безопасным и дружелюбным к интеграторам.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Telegram
@Gamble_GC
Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.