Kody błędów API i najlepsze praktyki
1) Dlaczego ujednolicić błędy
Przewidywalność dla klientów: pojedynczy format i zachowanie retras.
Przyspieszenie debugowania: 'trace _ id'/' request _ id', stabilny' error _ code '.
Bezpieczeństwo: SQL/stos śladów/konfiguracji nie wycieka.
Obserwowalność: sprawozdawczość w zakresie taksonomii błędów (walidacja, kwoty, terminy itp.).
2) Podstawowe zasady
1. Pojedynczy format odpowiedzi dla wszystkich 4xx/5xx (i dla 2xx z częściowymi błędami - oddzielny schemat).
2. Wyczyść semantykę HTTP: najważniejszy jest prawidłowy status.
3. Dwa poziomy kodu: transport („status”) i domena stabilna „error _ code”.
4. Retriable vs Non-retriable: wyraźnie określić i dać wskazówkę na temat cofnięcia.
5. Domyślne zabezpieczenie: szczegóły - tylko dla klienta z prawami; bez wewnętrznych śladów.
6. Lokalizacja: kod maszyny pozostaje stabilny, tekst - tłumaczymy.
3) Format pojedynczego błędu (na podstawie RFC 7807)
Zalecana JSON (rozszerzona „aplikacja/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"}
}
Wymagane: 'typ', 'tytuł', 'status', 'error _ code', 'trace _ id'.
Opcjonalnie: 'błędy []' (według pól), 'retriiable', 'hint', 'meta'.
- „Typ treści: aplikacja/problem + json”
- 'X-Request-ID'/' Traceparent' (W3C)
- (dla 429/503) „Retry-After” (sekundy lub data)
4) Semantyka statusów HTTP (połączenie „klasyki” i praktyki)
2xx (sukces niuansowany)
200 OK to wspólny sukces.
201 Stworzone - lokalizacja.
202 Akceptowane - asynchronicznie w kolejce (podaj 'status _ url').
207 Multi-Status - częściowy sukces (unikać, jeśli to możliwe).
4xx (błąd klienta)
400 Bad Request - składnia/format, ale nie walidacja pola (najlepiej 422).
401 Nieautoryzowany - nie/nieprawidłowy token. „WWW-Authenticate”.
403 Zakazane - token jest ważny, ale nie ma wystarczających praw (RBAC/ABAC/limits).
404 Nie znaleziono - brak zasobu/punktu końcowego.
409 Konflikt - optymalne blokowanie, idempotencja.
410 Odszedł - punkt końcowy usunięty na stałe.
412 Warunek wstępny nie powiódł się - ETag/If-Match nie powiódł się.
415 Unsupported Media Type - Invalid 'Content-Type'.
422 Podmiot nieprzetworzony - zatwierdzanie zasad prowadzenia działalności gospodarczej.
429 Zbyt wiele wniosków - przekroczył kwoty/prędkość (patrz § 7).
5xx (błąd serwera)
Błąd serwera wewnętrznego 500 - błąd nagły; nie ujawniać szczegółów.
502 Bad Gateway - błąd w górę strumienia.
503 Serwis Niedostępny - degradacja/przeciążenie, daj 'Retry-After'.
504 Gateway Timeout - backend timeout.
5) Taksonomia domeny „error _ code”
Zalecamy następujące zakresy:- 'AUTH _' - uwierzytelnianie/autoryzacja.
- „VAL _” - walidacja danych wejściowych.
- „RATELIMIT _” - kwoty i prędkość.
- „IDEMP _” - idempotencja/duplikaty.
- „CONFLICT _” - wersje/status.
- „DEP _” - zależności (PSP/DNS/SMTP).
- „PAY _” - błędy biznesowe domeny płatności.
- „SEC _” - bezpieczeństwo (podpisy, HMAC, mTLS).
- 'INT _' - nagły wewnętrzny.
- Stabilność w czasie (back-compat).
- Opisy i przykłady w katalogu błędów (docs + czytnik maszynowy JSON).
6) Retriable vs Non-retriable
Pola:- "retriable: true 'false'
- Jeśli 'true' - koniecznie 'Retry-After' (w sekundach) lub kontrakt 'wykładnicze cofnięcie (począwszy od 1-2 s, max 30-60 s)'.
Retriable zwykle: '502/503/504', some '500', '429' (po oknie).
Nie do odzyskania: „400/401/403/404/ 409/410/415/422”.
7) Limit stawek i błędy kwot (429)
Ciało: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
}
Tytuły:
- „Ponowna próba po: 12”
- 'Limit-Limit-X', 'Limit-Pozostały', 'X-Limit-Reset'
- Мла квой: „X-Quota-Limit”, „X-Quota-Remaining”, „X-Quota-Reset”
8) Idempotencja i konflikty
W żądaniach pisania - 'Idempotency-Key' (unikalne w ciągu 24-72 godzin).
Konflikt retry → 409 Konflikt z 'error _ code: "IDEMP_REPLAY"'.
Konflikt wersji zasobów dla ETag → 412 Warunek wstępny nie powiódł się.
W odpowiedzi należy dołączyć 'resource _ id'/' status _ url' dla bezpiecznego ponownego żądania.
9) Walidacja i 422
Zwróć listę błędów według pola:json
{
"status": 422,
"error_code": "VAL_001",
"errors": [
{"field":"email","code":"email_invalid","message":"Invalid email"},
{"field":"age","code":"min","message":"Must be >= 18"}
]
}
Zasady:
- Nie duplikuj tego samego w 400 - 422 preferowanych dla walidacji firmy.
- Wiadomości są czytelne dla ludzi; 'kod' nadaje się do odczytu maszynowego.
10) Bezpieczeństwo błędów
Nigdy: stos śladów, SQL, ścieżki plików, prywatne nazwy hosta.
Edytuj PII; pilnować RODO/DSAR.
W przypadku podpisu/HMAC należy rozróżnić 'SEC _ SIGNATURE _ MISMATCH' (403) i 'SEC _ TIMESTAMP _ SKEW' (401/403) z szybkością 'check ± time 5 min'.
11) Korelacja i obserwowalność
Zawsze dodawaj 'trace _ id'/' X-Request-ID' i przewijaj dzienniki/ścieżki.
Zagregowane błędy przez 'error _ code' i 'status' → deski rozdzielcze 'top errors',' new vs known '.
Wpisy: 5xx/422/429 spike, p95 latency, udział błędów.
12) gRPC/GraphQL/Webhooks - mapy
gRPC
GraphQL
Transport 200, ale 'błędy []' wewnątrz - dodać 'napięcia. kod „ка” trace _ id'.
Dla „śmiertelne” (uwierzytelnianie/kwoty) - prawdziwy 401/403/429 HTTP jest lepszy.
Haki internetowe
Rozważmy tylko 2xx odbiorców sukcesu.
Retrai z wykładniczym cofnięciem, 'X-Webhook-ID',' X-Signature '.
410 od odbiorcy - stop retray (punkt końcowy usunięty).
13) Weryfikacja błędów
„type ”/„ error _ code” - stabilny; nowy - dodaj tylko.
Podczas zmiany schematu ciała, podnieść małą wersję API lub 'problem + json; v = 2 '.
Dokumentacja: tabela kodowa + przykłady; błędy changelog.
14) Dokumentacja (fragmenty OpenAPI)
Reakcje globalne
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 }
Przykład punktu końcowego
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) Badania i jakość
Kontrakt testowy: match 'application/problem + json', wymagane pola.
Testy negatywne: wszystkie gałęzie 401/403/404/ 409/422/429/500.
Chaos/opóźnienie: sprawdzanie retras dla 5xx/ 503/504/429 („Retry-After”).
Testy bezpieczeństwa: brak komunikatów wewnętrznych, poprawna maska PII.
Wsteczny kompat: Starzy klienci rozumieją nowe pola (dodać, nie łamać).
16) Lista kontrolna wdrażania
- Pojedynczy „problem + json” + stabilny „error _ code”.
- Poprawność semantyki HTTP/gRPC/GraphQL.
- Zalecenia retriable/non-retriable + „Retry-After ”/back-off.
- Nagłówki limitu stawki i zachowanie 429.
- Idempotencja („Idempotency-Key”, 409/412).
- Bezpieczeństwo: brak śladów/tajemnic w stosie, wydanie PII.
- 'trace _ id'/' X-Request-ID' we wszystkich błędach.
- Dokumentacja i przykłady katalogu błędów.
- Monitorowanie za pomocą taksonomii błędów.
- Autotest negatywnych scenariuszy.
17) Mini-FAQ
Jak 400 różni się od 422?
400 - złamane żądanie (typ składni/zawartości). 422 - ważny w składni, ale zasady biznesowe nie przeszły.
Kiedy jest 401, a kiedy 403?
401 - nie/nieprawidłowy token; 403 - jest token, nie ma wystarczających praw.
Czy 'Retry-After' always jest potrzebny?
Dla 429/503, tak; dla reszty, retriable - wskazane jest, aby dać wyraźne zalecenie.
Razem
Dobrze zaprojektowane błędy to umowa: poprawny status HTTP, pojedynczy 'problem + json', stabilny 'error _ code', wyraźne podpowiedzi retrasy i silne bezpieczeństwo. Standaryzuj format, dokumentuj taksonomię, dodaj telemetrię i testy - a Twój interfejs API staje się przewidywalny, bezpieczny i przyjazny dla integratora.