Guide 5 af 8
Fejl og rate limits
Alle fejl er JSON og har mindst et message. Nogle har mere.
{ "message": "Unauthenticated." }Statuskoderne
| Kode | Betyder | Hvad du gør |
|---|---|---|
200 |
OK | |
401 |
Nøglen mangler, er ukendt, spærret eller udløbet | Stop. Genforsøg hjælper ikke |
403 |
Nøglen er gyldig, men mangler et scope | Stop. Opret en nøgle med det rigtige scope |
404 |
Ressourcen findes ikke i din organisation | Stop. Se nedenfor |
422 |
Ugyldige parametre | Ret input |
429 |
For mange kald | Vent, og genforsøg efter Retry-After |
5xx |
Fejl hos os | Genforsøg med eksponentiel backoff |
Kun 429 og 5xx er værd at genforsøge automatisk. Alt andet er en fejl i kaldet, og et blindt genforsøg gør det bare til den samme fejl igen, hurtigere.
403 fortæller hvilket scope der mangler
{
"message": "Insufficient scope.",
"required_scope": "invoices:read"
}required_scope er der så din log kan sige "nøglen mangler invoices:read" i stedet for "adgang nægtet". Værdien er altid et navn fra scope-kataloget, aldrig fri tekst.
404 er også svaret på "findes i en anden organisation"
Det her overrasker de fleste, og det er med vilje.
Slår du et id op der findes, men hører til en anden organisation, får du 404, ikke 403. Der er intet i svaret der skelner de to tilfælde fra hinanden.
Grunden er at 403 ville være en oplysning. "Du må ikke se den her" bekræfter at rækken eksisterer, og med et endpoint der svarer forskelligt på "findes ikke" og "findes, men ikke hos dig" kan man afprøve id'er indtil man har kortlagt en anden organisations sager. Det hedder et enumeration-hul, og den eneste sikre rettelse er at de to tilfælde ser ens ud.
Så i din fejlhåndtering: 404 betyder "ikke her". Læs det ikke som "slettet", og skriv ikke en oprydning der sletter lokale rækker på et enkelt 404.
422 samler feltfejlene
{
"message": "The given data was invalid.",
"errors": {
"per_page": ["The per page must be an integer."]
}
}errors er et objekt med et feltnavn per nøgle og en liste af beskeder. Feltnavnene er dem fra forespørgslen, så du kan sætte dem direkte på din egen formular.
Rate limits
Grænsen tælles pr. nøgle, ikke pr. IP. Standard er 120 kald i minuttet. Flere servere bag samme nøgle deler altså puljen, og to nøgler fra samme maskine gør ikke.
Hvert autentificeret svar bærer status med:
| Header | Indhold |
|---|---|
X-RateLimit-Limit |
Kald tilladt i vinduet |
X-RateLimit-Remaining |
Kald tilbage i det nuværende vindue |
X-RateLimit-Reset |
Unix-tidsstempel for hvornår vinduet nulstilles |
Rammer du loftet, får du 429 og en Retry-After i sekunder.
import time, requests
def call(url, headers, attempt=1):
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 429 and attempt <= 5:
time.sleep(int(response.headers.get("Retry-After", 5)))
return call(url, headers, attempt + 1)
response.raise_for_status()
return response.json()Læs Retry-After frem for at gætte. Et fast sleep(1) i en løkke er den sikreste måde at holde sig selv i 429 resten af minuttet.
Vil du ikke ramme loftet i første omgang: hent større sider frem for flere. per_page=100 henter det samme som fire kald med per_page=25, for ét kald af budgettet.
Det uautentificerede endpoint /api/v1/openapi.json har sin egen, lavere grænse, fordi den ikke kan tælles pr. nøgle.
Hvad du ikke får i en fejl
Fejl indeholder ikke stack traces, interne id'er eller besked om hvilken organisation en ressource ellers ligger i. Kan du ikke se hvad der gik galt af message alene, så skriv til os med tidspunkt, endpoint og navnet på nøglen. Vi kan slå kaldet op i vores egne logs. Nøglens hemmelighed skal du ikke sende med.