Erori
Sursa folosește codurile de status HTTP pentru a spune dacă o cerere a reușit și un cod de eroare stabil pentru a spune de ce nu a reușit. Fiecare răspuns de eroare are aceeași formă:
{
"detail": "the cursor is malformed or was issued for different filters",
"error": {
"code": "api.cursor_invalid",
"message": "the cursor is malformed or was issued for different filters",
"details": {"parameter": "cursor"},
"request_id": "01JB7Q2M4X9V3K8T5N6P0R1S2A",
"doc_url": "https://developers.sursa.com/errors/api.cursor_invalid"
}
}
| Câmp | Semnificație |
|---|---|
error.code | Cod stabil de forma <area>.<reason>. Ramificați codul după el. |
error.message | O explicație lizibilă în engleză. Poate fi reformulată oricând; nu o analizați. |
error.details | Date structurate despre eroare, cum ar fi parametrul, o limită sau momentul reîncercării. Câmpurile depind de cod. |
error.request_id | Identificatorul acestei cereri, același ca în antetul de răspuns X-Request-Id. |
error.doc_url | Pagina despre acest cod din acest portal. |
detail | Forma anterioară a erorii, păstrată pentru integrările existente. Codul nou ar trebui să citească error. |
Fiecare cod are propria pagină în Coduri de eroare, cu statusul HTTP, câmpurile din details și
endpointurile care îl returnează. Pagina fiecărui endpoint din referința API enumeră codurile pe care
le poate returna acel endpoint.
Statusuri HTTP
| Status | Semnificație |
|---|---|
200, 201, 202, 204 | Cererea a reușit. 202 înseamnă că a fost acceptată și este încă în curs de procesare. |
400 | Cererea este formată greșit: un parametru, un cursor, metadata sau un Idempotency-Key greșit. Corectați cererea. |
401 | Nu există o cheie validă. Vedeți Autentificare. |
402 | S-a atins o limită a planului organizației, de exemplu numărul de fișe sau spațiul de stocare. |
403 | Cheia este validă, dar nu are voie să facă acest lucru: lipsește un rol, un domeniu de acces sau o funcție a planului. |
404 | Obiectul nu există sau cheia nu are voie să-l vadă. |
409 | Cererea intră în conflict cu starea curentă: un external_id duplicat, o sincronizare deschisă, o cerere cu același Idempotency-Key încă în execuție. |
410 | Obiectul a expirat, de exemplu o încărcare după 24 de ore, sau ruta a fost retrasă. |
413 | Corpul sau fișierul este prea mare. |
415 | Tipul fișierului nu este acceptat sau conținutul lui nu corespunde numelui. |
422 | Cererea este formată corect, dar este invalidă: lipsește un câmp sau o valoare este în afara intervalului. |
429 | Prea multe cereri sau o cotă epuizată. Vedeți Limite de frecvență și cote. |
500, 502, 503, 504 | O problemă din partea Sursa. Reîncercați mai târziu. |
Erori de validare
Pentru 422 cu codul validation.failed, detail enumeră fiecare câmp care nu a
trecut validarea, fiecare cu locul lui:
{
"detail": [
{"loc": ["body", "title"], "msg": "String should have at least 1 character", "type": "string_too_short"}
],
"error": {"code": "validation.failed", "message": "request validation failed", "request_id": "01JB7…"}
}
Ce erori trebuie reîncercate
| Eroare | Reîncercați? |
|---|---|
| Eroare de rețea sau expirare, fără răspuns | Da, cu același Idempotency-Key. |
429 | Da, după numărul de secunde din Retry-After. |
500, 502, 503, 504 | Da, cu așteptare exponențială: 1 s, 2 s, 4 s… până la un minut, cu o variație aleatoare (jitter). |
409 api.idempotency_in_progress | Da, după Retry-After: prima cerere cu această cheie este încă în execuție. |
Orice alt 4xx | Nu. Aceeași cerere va eșua din nou; corectați-o mai întâi. |
Reîncercați cererile POST și PATCH doar cu un Idempotency-Key, ca o reîncercare
după un răspuns pierdut să nu poată crea un al doilea obiect. GET, PUT și DELETE pot fi reîncercate în siguranță
așa cum sunt.
// Retries a request on network errors, 429 and 5xx. The same Idempotency-Key is sent on every attempt.
async function withRetries(send, attempts = 5) {
for (let attempt = 1; ; attempt++) {
let response;
try {
response = await send();
} catch (error) {
if (attempt >= attempts) throw error;
}
if (response && response.status !== 429 && response.status < 500) return response;
if (attempt >= attempts) return response;
const retryAfter = Number(response?.headers.get("Retry-After"));
const backoff = Math.min(60, 2 ** (attempt - 1)) * (0.8 + Math.random() * 0.4);
await new Promise((resolve) => setTimeout(resolve, 1000 * (retryAfter || backoff)));
}
}
const key = crypto.randomUUID();
const response = await withRetries(() =>
fetch("https://api.sursa.com/v1/cards/text", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SURSA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": key,
},
body: JSON.stringify({ title: "Refund policy", body_markdown: "Refunds take 14 days." }),
}),
);Raportarea unei probleme
Fiecare răspuns, reușit sau nu, are un antet X-Request-Id, iar fiecare eroare are aceeași valoare în
error.request_id. Înregistrați-l în jurnal împreună cu propria evidență a cererii. Când contactați asistența
tehnică despre o cerere, trimiteți ID-ul cererii: el duce direct la înregistrarea acelei cereri.
Tratarea codurilor necunoscute
Coduri de eroare noi pot apărea în orice versiune a API-ului. Tratați un cod necunoscut după statusul HTTP: un 4xx
necunoscut ca o cerere care nu va reuși așa cum este, un 5xx necunoscut ca o problemă temporară.