GH GambleHub

Обробка помилок і коди статусів

1) Навіщо стандартизувати помилки

Єдиний контракт помилок прискорює налагодження клієнтів, знижує помилкові ретраї і робить RCA відтворюваним. Хороша система:
  • передбачувано кодує тип проблеми,
  • дає клієнту дійсні підказки (що робити далі),
  • захищає від витоку внутрішніх деталей,
  • сумісна з ретраями та ідемпотентністю.

2) Принципи дизайну

1. Одна схема помилок для всіх сервісів (REST/GraphQL/gRPC/webhooks).
2. Чітка семантика ретраїв: які коди ретраїти, які - ні.
3. Fail-closed на write-операціях: краще 4xx/5xx, ніж тиха неконсистентність.
4. Без витоків: не розкривати SQL, стеки, конфіги, внутрішні ID.
5. Трасування: завжди повертайте'trace _ id '/' correlation _ id'.
6. Локалізація повідомлень - опціонально, але коди і «reason» залишаються стабільними.


3) Єдиний формат (Problem Details/JSON)

Рекомендований базовий формат (сумісний з RFC 7807):
json
{
"type": "https://errors.example.com/auth/invalid-token",
"title": "Invalid access token",
"status": 401,
"code": "AUTH_INVALID_TOKEN",
"detail": "Token expired or signature invalid.",
"instance": "/api/v1/payments/12345",
"trace_id": "01HX3...ABC",
"hint": "Obtain a new token via OAuth2 refresh.",
"meta": {
"scope": "payments:write",
"policy": "deny-by-default"
}
}
Пояснення:
  • 'type'- стабільний URL-ідентифікатор класу помилок.
  • «code» - короткий машинний код домену (стабільний між релізами).
  • 'hint'- що робити клієнту (повтор, оновити токен, змінити параметри).
  • «meta» - безпечні деталі (без секретів і PII).

4) Карта кодів статусів (мінімальний набір)

Автентифікація/авторизація

400 Bad Request - структурна валідація/схема.
401 Unauthorized - ні/неваліден токен. Додавайте'WWW-Authenticate'.
403 Forbidden - автентифікований, але немає прав/політики відмовили.
404 Not Found - маскуйте існування ресурсу за відсутності прав.
409 Conflict - конфлікт версій/станів (optimistic lock, ідемпотентність).
451 Unavailable For Legal Reasons - блок по комплаєнсу/юрисдикції.

Ліміти та захист

408 Request Timeout - клієнт занадто повільно відправляє тіло.
409/425 Too Early - заборона раннього повтору в 0-RTT/TLS 1. 3.
429 Too Many Requests - з «Retry-After» і політикою ліміту.
499 Client Closed Request - (на периметрі/NGINX) клієнт розірвав з'єднання.

Дані та бізнес-правила

422 Unprocessable Content - бізнес-валідація пройшла схему, але сенс невірний.
423 Locked - ресурс заблокований (KYC review, AML freeze).
409 Conflict - подвійна відправка, гонка, ліміт стану (наприклад, «вже в обробці»).
410 Gone - ендпоінт/ресурс видалений (депрекейт завершений).

Серверні

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

💡 Правило: write-операції при сумніві → 409 (конфлікт) або 503 (повтор пізніше), не 200.

5) Семантика ретраїв та ідемпотентності

Не можна ретраїти: 400/ 401/403/404/422 (якщо клієнт не змінив запит).
Можна ретраїти: 408/429/5xx/425/499/504 (с backoff + jitter).
Ідемпотентність: для'POST'включайте'Idempotency-Key'( UUIDv4).

На конфлікт повторного виконання повертайте 409 з'hint: "Use same Idempotency-Key or GET status"`.
Додавайте'Idempotency-Replay: true'при поверненні збереженого результату.

Приклад headers при 429:

HTTP/1.1 429 Too Many Requests
Retry-After: 3
RateLimit-Limit: 50
RateLimit-Remaining: 0
RateLimit-Reset: 1730641030

6) Валідація входу: структура помилок полів

Для 400/422 використовуйте масив помилок полів:
json
{
"type": "https://errors.example.com/validation",
"title": "Validation failed",
"status": 422,
"code": "VALIDATION_ERROR",
"trace_id": "01HX4...XYZ",
"errors": [
{"field": "amount", "rule": "min", "message": "Must be >= 10"},
{"field": "currency", "rule": "enum", "message": "Unsupported currency"}
]
}

7) Часткові невдачі (batch/partial failure)

У батч-ендпоінтах не ховайте помилки всередині 200 без структури. Повертайте 207 Multi-Status або 200 c масивом результатів, де кожне завдання має свій статус:
json
{
"status": "partial",
"succeeded": 8,
"failed": 2,
"results": [
{"id": "op1", "status": 201},
{"id": "op2", "status": 422, "error": {"code":"VALIDATION_ERROR","detail":"..."}}
]
}

8) Пагінація і «порожні» відповіді

Порожня колекція - 200 с'items: []', не 404.
Кінець сторінки -'next _ page _ token'відсутній.
Некоректний токен - 400 с'code: PAGINATION_CURSOR_INVALID`.


9) Webhooks: Надійна доставка

Підписуйте події (HMAC) і перевіряйте до обробки.
Відповідь на успішну обробку - 2xx (краще 204).
Тимчасові збої одержувача - 5xx; відправник повторює (експоненціальний backoff, джиттер).
Дедуплікація по'event _ id'і збереження результату (idempotent consumer).
Неприпустимий payload - 400/422 без повторів.


10) Відповідності протоколам (gRPC/GraphQL)

gRPC → HTTP:
  • `INVALID_ARGUMENT` → 400
  • `UNAUTHENTICATED` → 401
  • `PERMISSION_DENIED` → 403
  • `NOT_FOUND` → 404
  • `ALREADY_EXISTS` → 409
  • `FAILED_PRECONDITION` → 412/422
  • `RESOURCE_EXHAUSTED` → 429
  • `ABORTED` → 409
  • `UNAVAILABLE` → 503
  • `DEADLINE_EXCEEDED` → 504
GraphQL: завжди 200 на транспортному рівні припустимо, але поміщайте помилки в'errors []'і дублюйте в заголовках/розширеннях:
json
{
"data": { "createPayment": null },
"errors": [{
"message": "Forbidden",
"extensions": { "code": "FORBIDDEN", "status": 403, "trace_id": "..." },
"path": ["createPayment"]
}]
}

Рекомендується для критичних помилок використовувати не 200, а відповідний HTTP-код.


11) Заголовки та підказки клієнту

«Retry-After» - секунди/НТТР-дата (429/503/425/408).
«Warning» - м'які деградації або депрекейт («199 - Feature X is deprecated»).
`Deprecation`, `Sunset`, `Link: <...>; rel = «deprecation»'- для керованого відключення.
«Problem-Type» (кастомний) - швидкий роутинг помилок на клієнті.
'X-Trace-Id '/' Correlation-Id'- зв'язує логи/трейси.


12) Безпека повідомлень

Не повторюйте вхідні секрети (токени/підписи) в тілі відповіді.
Маскуйте PAN/PII ('1234').
Для 401/403 - не розкривайте, який саме атрибут провалився.
Для 404 замість «resource exists but not yours» - просто 404.


13) Спостережуваність помилок

Метрики:
  • `http_errors_total{status, route, tenant}`
  • 'error _ classes _ total {code}'( по'code'з тіла)
  • частка 429, 5xx;'p95 '/' p99'latency для помилкових відповідей окремо
  • 'retry _ after _ seconds _ bucket'- гістограма порад по повторах
Логи/трейси:
  • зв'язуйте відповідь з «trace _ id», зберігайте «code», «type», «status», «route», «tenant», без PII.
Алерти:
  • сплеск'5xx _ rate> X%'при RPS> N;
  • зростання 429 на критичних маршрутах;
  • 'timeout/504'у залежностей;
  • часті 409/ідемпотентність → ознака гонок.

14) Приклади

14. 1 422 (бізнес-валідація)

json
{
"type": "https://errors.example.com/payments/limit-exceeded",
"title": "Limit exceeded",
"status": 422,
"code": "PAYMENT_LIMIT_EXCEEDED",
"detail": "Daily withdrawal limit reached for KYC1.",
"hint": "Increase limits after KYC2 or try tomorrow.",
"trace_id": "01J5...XYZ"
}

14. 2 409 (ідемпотентність)


HTTP/1.1 409 Conflict
Idempotency-Replay: true
json
{
"type": "https://errors.example.com/idempotency/replay",
"title": "Duplicate request",
"status": 409,
"code": "IDEMPOTENT_REPLAY",
"detail": "A request with the same Idempotency-Key was already processed.",
"hint": "Reuse the same Idempotency-Key and GET the operation status."
}

14. 3 429 (ліміти)

json
{
"type":"https://errors.example.com/rate/too-many-requests",
"title":"Too many requests",
"status":429,
"code":"RATE_LIMITED",
"detail":"Per-key rate limit exceeded.",
"hint":"Retry after the time specified in Retry-After header."
}

15) Антипатерни

Повертати 200 з текстом помилки в тілі.
Змішувати різні формати помилок між сервісами.
Розкривати стек/SQL/імена таблиць/внутрішні URL в'detail'.
Використовувати «message» замість стабільного «code »/« type».
Повертати 500 при очікуваній бізнес-помилці (наприклад, «баланс недостатній»).
Непослідовна семантика між REST/GraphQL/gRPC.


16) Специфіка iGaming/фінансів

Чіткі коди для KYC/AML/санкцій: `KYC_REQUIRED`, `KYC_REVIEW`, `AML_LOCK`, `SANCTION_BLOCKED`.
Обмеження юрисдикцій: 451 з безпечним формулюванням без зазначення списків.
Грошові write-операції: 409/423 при конкуренції і блокуваннях,'hint'з вікном повтору.
Інваріанти лімітів гравця: використовуйте 422 для порушень правил відповідальних платежів.
Аудит: незмінювані журнали рішень (код, час, актор, trace_id).


17) Чек-лист prod-готовності

  • Єдина JSON-схема помилок, стабільні'type '/' code'.
  • Маппінг HTTP ↔ gRPC/GraphQL узгоджений і задокументований.
  • Семантика ретраїв +'Retry-After'; ідемпотентність для write.
  • Маскування PII/секретів; 404 для приховування ресурсів.
  • Метрики помилок і алерти; кореляція з'trace _ id'.
  • Політики депрекейту: `Deprecation`, `Sunset`, `Link`.
  • Тести: negative/fuzz, конфлікт версій, падіння залежностей, double-submit.
  • Гайд клієнтам: приклади бек-оффів і обробка 409/422/429/5xx.

18) TL; DR

Стандартизуйте єдиний JSON-формат помилок c'type '/' code '/' trace _ id', використовуйте коректні HTTP-коди, розрізняйте валідацію (400/422), права (401/403/404), конфлікти/ідемпотентність (409) і ліміти (429). Давайте чіткі'Retry-After'і'hint', маскуйте чутливі дані, логуйте помилки з'trace _ id'і будуйте алерти по 5xx/429/p99.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.