ข้อผิดพลาด
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 | ลองใหม่ ด้วย backoff แบบเอ็กซ์โพเนนเชียล: 1 วินาที 2 วินาที 4 วินาที… ไม่เกิน 1 นาที พร้อมการสุ่มเวลา (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 ที่ไม่รู้จักให้ถือว่าเป็นปัญหาชั่วคราว