Lỗi
Sursa dùng mã trạng thái HTTP để cho biết yêu cầu có thành công hay không, và một mã lỗi ổn định để cho biết vì sao không thành công. Mọi phản hồi lỗi có cùng một cấu trúc:
{
"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"
}
}
| Trường | Ý nghĩa |
|---|---|
error.code | Mã ổn định dạng <area>.<reason>. Hãy rẽ nhánh mã của bạn theo trường này. |
error.message | Lời giải thích dễ đọc bằng tiếng Anh. Nó có thể được viết lại bất cứ lúc nào; đừng phân tích nó. |
error.details | Các dữ kiện có cấu trúc về lỗi, chẳng hạn tham số, một giới hạn, hoặc khi nào nên thử lại. Các trường của nó phụ thuộc vào mã. |
error.request_id | ID của yêu cầu này, giống header phản hồi X-Request-Id. |
error.doc_url | Trang về mã này trên cổng này. |
detail | Dạng lỗi trước đây, được giữ lại cho các tích hợp hiện có. Mã mới nên đọc error. |
Mỗi mã có trang riêng trong Mã lỗi, với trạng thái HTTP, các trường của details và các endpoint trả về
nó. Trang của mỗi endpoint trong tài liệu tham chiếu API liệt kê các mã mà endpoint đó có thể trả về.
Trạng thái HTTP
| Trạng thái | Ý nghĩa |
|---|---|
200, 201, 202, 204 | Yêu cầu thành công. 202 nghĩa là yêu cầu đã được chấp nhận và vẫn đang được xử lý. |
400 | Yêu cầu sai định dạng: tham số, con trỏ, metadata hoặc Idempotency-Key không đúng. Hãy sửa yêu cầu. |
401 | Không có khóa hợp lệ. Xem Xác thực. |
402 | Đã chạm một giới hạn của gói của tổ chức, chẳng hạn số lượng thẻ hoặc dung lượng lưu trữ. |
403 | Khóa hợp lệ nhưng không được phép làm việc này: thiếu vai trò, phạm vi quyền hoặc tính năng của gói. |
404 | Đối tượng không tồn tại, hoặc khóa không được phép xem nó. |
409 | Yêu cầu xung đột với trạng thái hiện tại: external_id bị trùng, một phiên đồng bộ đang mở, một yêu cầu với cùng Idempotency-Key vẫn đang chạy. |
410 | Đối tượng đã hết hạn, chẳng hạn một lượt tải lên sau 24 giờ, hoặc tuyến API đã ngừng hoạt động. |
413 | Phần thân hoặc tệp quá lớn. |
415 | Loại tệp không được hỗ trợ, hoặc nội dung tệp không khớp với tên của nó. |
422 | Yêu cầu đúng định dạng nhưng không hợp lệ: thiếu trường hoặc giá trị nằm ngoài khoảng cho phép. |
429 | Quá nhiều yêu cầu hoặc đã dùng hết hạn mức. Xem Giới hạn tốc độ và hạn mức. |
500, 502, 503, 504 | Sự cố phía Sursa. Hãy thử lại sau. |
Lỗi dữ liệu không hợp lệ
Với 422 và mã validation.failed, detail liệt kê mọi trường không hợp lệ, mỗi
trường kèm vị trí của nó:
{
"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…"}
}
Lỗi nào nên thử lại
| Lỗi | Thử lại? |
|---|---|
| Lỗi mạng hoặc hết thời gian chờ, không có phản hồi | Có, với cùng Idempotency-Key. |
429 | Có, sau số giây ghi trong Retry-After. |
500, 502, 503, 504 | Có, với backoff lũy thừa (khoảng chờ tăng dần): 1 giây, 2 giây, 4 giây… tối đa một phút, kèm jitter (độ lệch ngẫu nhiên). |
409 api.idempotency_in_progress | Có, sau Retry-After: yêu cầu đầu tiên với khóa này vẫn đang chạy. |
Mọi 4xx khác | Không. Cùng yêu cầu đó sẽ lại thất bại; hãy sửa nó trước. |
Chỉ thử lại yêu cầu POST và PATCH khi có Idempotency-Key, để lần thử lại sau khi
mất phản hồi không thể tạo ra đối tượng thứ hai. GET, PUT và DELETE có thể thử lại nguyên trạng một cách an
toàn.
// 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." }),
}),
);Báo cáo sự cố
Mọi phản hồi, thành công hay không, đều có header X-Request-Id, và mọi lỗi có cùng giá trị đó trong
error.request_id. Hãy ghi nó vào nhật ký cùng bản ghi của bạn về yêu cầu. Khi liên hệ bộ phận hỗ trợ về một yêu cầu,
hãy gửi ID yêu cầu của nó: ID này dẫn thẳng tới bản ghi của yêu cầu đó.
Xử lý các mã bạn không biết
Mã lỗi mới có thể xuất hiện trong bất kỳ phiên bản nào của API. Hãy xử lý mã không xác định theo trạng thái HTTP của
nó: một 4xx không xác định là yêu cầu sẽ không thành công nếu giữ nguyên, một 5xx không xác định là sự cố tạm thời.