Грешки
Sursa използва HTTP кодовете на статуса, за да каже дали заявката е успяла, и стабилен код на грешка, за да каже защо не е успяла. Всеки отговор с грешка има една и съща структура:
{
"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"
}
}
| Поле | Значение |
|---|---|
error.code | Стабилен код във вида <area>.<reason>. Разклонявайте кода си по него. |
error.message | Четимо обяснение на английски. Може да бъде преформулирано по всяко време; не го анализирайте програмно. |
error.details | Структурирани факти за грешката, например параметърът, лимит или кога да опитате отново. Полетата му зависят от кода. |
error.request_id | ID на тази заявка, същото като в заглавката на отговора X-Request-Id. |
error.doc_url | Страницата за този код в този портал. |
detail | По-ранният вид на грешката, запазен за съществуващите интеграции. Новият код трябва да чете error. |
Всеки код има собствена страница в Кодове на грешки с HTTP статуса му, полетата на details и
операциите, които го връщат. Страницата на всяка операция в справочника на API изброява кодовете,
които операцията може да върне.
HTTP статуси
| Статус | Значение |
|---|---|
200, 201, 202, 204 | Заявката е успешна. 202 означава, че е приета и все още се обработва. |
400 | Заявката е неправилно съставена: грешен параметър, курсор, metadata или Idempotency-Key. Поправете заявката. |
401 | Няма валиден ключ. Вж. Удостоверяване. |
402 | Достигнат е лимит на плана на организацията, например броят на картите или обемът на хранилището. |
403 | Ключът е валиден, но няма право да прави това: липсва роля, обхват или функция на плана. |
404 | Обектът не съществува или ключът няма право да го вижда. |
409 | Заявката противоречи на текущото състояние: повтарящ се external_id, отворена синхронизация, заявка със същия Idempotency-Key, която все още се изпълнява. |
410 | Срокът на обекта е изтекъл, например на качване след 24 часа, или маршрутът е спрян. |
413 | Тялото или файлът е твърде голям. |
415 | Типът на файла не се поддържа или съдържанието му не съответства на името му. |
422 | Заявката е правилно съставена, но е невалидна: липсва поле или стойност е извън диапазона. |
429 | Твърде много заявки или квотата е изчерпана. Вж. Лимити на честотата и квоти. |
500, 502, 503, 504 | Проблем от страна на Sursa. Опитайте отново по-късно. |
Грешки при валидиране
При 422 с кода validation.failed detail изброява всяко поле, което не е
преминало проверката, заедно с местоположението му:
{
"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…"}
}
Кои грешки да опитате отново
| Грешка | Повторен опит? |
|---|---|
| Мрежова грешка или изтичане на времето за изчакване, няма отговор | Да, със същия Idempotency-Key. |
429 | Да, след броя секунди в Retry-After. |
500, 502, 503, 504 | Да, с експоненциално нарастваща пауза: 1 s, 2 s, 4 s… до минута, със случайно отклонение (jitter). |
409 api.idempotency_in_progress | Да, след Retry-After: първата заявка с този ключ все още се изпълнява. |
Всеки друг 4xx | Не. Същата заявка пак ще се провали; първо я поправете. |
Опитвайте отново заявки POST и PATCH само с Idempotency-Key, за да не може
повторен опит след изгубен отговор да създаде втори обект. GET, PUT и DELETE може безопасно да се опитват
отново такива, каквито са.
// 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." }),
}),
);Съобщаване за проблем
Всеки отговор, успешен или не, има заглавка X-Request-Id, а всяка грешка има същата стойност в
error.request_id. Записвайте я в дневника заедно със собствения си запис за заявката. Когато се свързвате с
поддръжката относно заявка, изпратете нейното ID: то води направо до записа за тази заявка.
Обработка на непознати кодове
Нови кодове на грешки може да се появят във всяка версия на API. Обработвайте непознат код по HTTP статуса му:
непознат 4xx – като заявка, която няма да успее в този вид, непознат 5xx – като временен проблем.