Errori
Un unico documento di problema leggibile dalle macchine per ogni errore, e cosa significa ciascun tipo per la sua logica di ritentativo.
Ogni errore — compresa una rotta che non esiste — risponde con
application/problem+json, la forma definita dalla RFC 9457. Non esiste alcun
percorso in questa API che restituisca una pagina di errore HTML, quindi un
parser che dà per scontato il JSON su una risposta non 2xx è al sicuro.
{
"type": "https://api.backresto.com/problems/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "The authenticated client lacks the required scope.",
"instance": "/v1/restaurants/restaurant-1/deliveries/8f2c/images",
"requestId": "b1c8b0a4-6c1e-4f6b-9e1c-3b2a5d7f0e91"
}
type è l'identificatore stabile: si ramifichi su quello, non su detail, che
è prosa e può essere riformulato. requestId è il valore da citare in un
messaggio al supporto — viene restituito anche nell'header di risposta
X-Request-ID, e può impostare lei stesso quell'header per correlare con le sue
tracce.
Il catalogo
Suffisso di type | Stato | Cosa è successo | Ritentare? |
|---|---|---|---|
invalid-request | 400 | Manca un parametro oppure è malformato: un intervallo di consegne invertito o troppo lungo, una collezione sconosciuta, oppure un cursore che non corrisponde al ristorante, alla collezione e al limit con cui sta paginando. | No — corregga la richiesta. |
unauthorized | 401 | Nessun header Authorization, oppure una chiave malformata, sconosciuta, revocata, scaduta o rimasta senza alcuna concessione. | No — la chiave richiede attenzione. |
forbidden | 403 | La chiave ha una concessione per questo ristorante ma non l'ambito richiesto da questo endpoint. | No — il cliente deve far emettere una chiave con quell'ambito. |
not-found | 404 | Nessuna concessione per questo ristorante, oppure quella consegna o quel record non esistono. I casi sono deliberatamente indistinguibili. | No. |
conflict | 409 | La richiesta è in conflitto con una risorsa esistente. | No. |
payload-too-large | 413 | Il corpo della richiesta supera il limite. | No. |
rate-limit-exceeded | 429 | Il suo client ha superato il proprio budget di richieste. | Sì, dopo Retry-After. |
dependency-unavailable | 503 | Un componente necessario all'API è momentaneamente non disponibile. | Sì, con backoff. |
internal-error | 500 | Un errore imprevisto, già registrato da parte nostra. | Una volta, con backoff; poi ci comunichi il requestId. |
Cosa dovrebbe fare un client
Tre categorie, e nient'altro vale il codice che costa:
Non ritentare — 400, 401, 403, 404, 409, 413. La richiesta fallirà di nuovo
in modo identico. Registri il type e il requestId, e li porti in superficie:
un 401 in particolare significa che una persona dalla parte del suo cliente ha
revocato qualcosa, e un ciclo di tentativi non farà che nasconderlo per una
settimana.
Ritentare con backoff — 429, 503. Rispetti Retry-After su un 429; è il
numero di secondi prima che il suo budget si ricarichi, e non è un suggerimento.
Per il 503, backoff esponenziale con jitter, e rinunci invece di martellare.
Ritentare una volta, poi segnalare — 500. Se si ripete sulla stessa richiesta, non è transitorio.
Ogni endpoint di questa API è un GET, quindi ritentare è sempre sicuro dal
punto di vista dell'API; il motivo per non ritentare un 4xx è che spreca il suo
budget, non che rischia una doppia scrittura.
Correlare con i suoi log
Invii un suo identificatore e le torna indietro:
curl "https://api.backresto.com/v1/restaurants/$RESTAURANT_ID/deliveries?from=1787846400000&to=1787932800000" \
-H "Authorization: Bearer $BACKRESTO_PARTNER_API_KEY" \
-H "X-Request-ID: 3f7a1c9e-2b4d-4a86-9f0c-5e1d8b6a2c40" \
--include
Il valore viene riproposto nell'header di risposta e nel requestId di un
documento di problema, il che fa sì che un solo grep risponda a «cosa ha visto
BackResto quando il mio job è fallito alle 04:12?».