ข้อผิดพลาดและการแบ่งหน้า
รูปแบบข้อผิดพลาด รหัสสถานะที่จะพบ และวิธีแบ่งหน้าของ endpoint รายการ
รูปแบบการห่อข้อมูล (envelope)
endpoint ส่วนใหญ่ห่อข้อมูลไว้ในคีย์ data
{
"success": true,
"data": { "id": 1, "name": "Widget" }
}งานเขียนที่ไม่มีข้อมูลจะคืน จะตอบเป็นข้อความแทน — เช่นการแก้ไข (PATCH) ส่วนใหญ่
{ "success": true, "message": "Update Success" }แต่มีบางกลุ่ม — ผู้ติดต่อ เอกสารขาย และข้อมูลองค์กร — ที่คืน object ตรง ๆ โดยไม่ห่อด้วย data
{ "id": 1, "documentNumber": "IV-2026-0001", "documentType": "IV" }และการลบจะตอบ 204 No Content โดยไม่มี body
เนื่องจากรูปแบบต่างกันตามกลุ่ม endpoint ควรเขียนไคลเอนต์ให้ตรวจรูปร่างของข้อมูล ไม่ใช่สมมติว่าเป็นแบบเดียว
// ใช้ได้ทั้งกับ { data: T } และ T เปล่า ๆ
function unwrap<T>(body: unknown): T {
if (body && typeof body === "object" && "data" in body) {
return (body as { data: T }).data;
}
return body as T;
}หน้าคู่มือของแต่ละ endpoint ระบุไว้ว่ากลุ่มนั้นคืนรูปแบบใด
รูปแบบข้อผิดพลาด
ทุก 4xx และ 5xx ใช้ body รูปแบบเดียวกัน
{
"statusCode": 400,
"errorCode": "BadRequest",
"errorMessage": "invalid request",
"errorDescription": "issueDate must be YYYY-MM-DD",
"errorValidation": [
{
"field": "DocumentType",
"tag": "oneof",
"message": "documentType must be one of: QT, SO, IV, RE, CS, CN, DN"
}
]
}| ฟิลด์ | หมายเหตุ |
|---|---|
statusCode | ตรงกับ HTTP status |
errorCode | รหัสที่เครื่องอ่านได้และคงที่ — ให้แยกเงื่อนไขด้วยค่านี้ ไม่ใช่ด้วยข้อความ |
errorMessage | ข้อความสั้น แปลตาม Accept-Language นำไปแสดงให้ผู้ใช้ได้ |
errorDescription | รายละเอียดเพิ่มเติมสำหรับนักพัฒนา มีเฉพาะบางกรณี |
errorValidation | หนึ่งรายการต่อหนึ่งฟิลด์ที่ไม่ผ่าน มีเฉพาะข้อผิดพลาดด้านการตรวจสอบข้อมูล |
errorValidation[].field เป็นชื่อฟิลด์ในโครงสร้างฝั่งเซิร์ฟเวอร์ (DocumentType) ไม่ใช่ชื่อคีย์ JSON (documentType) หากต้องการแมปกลับไปที่ payload ให้เปลี่ยนอักษรตัวแรกเป็นตัวเล็ก (และเปลี่ยน ID เป็น Id เมื่อมี) สำหรับฟิลด์ที่เป็น enum อย่าง documentType ตัว message จะระบุค่าที่ยอมรับไว้ให้เลย เช่น "documentType must be one of: QT, SO, IV, RE, CS, CN, DN"
รหัสสถานะ
| รหัส | ความหมาย | ควรทำอะไร |
|---|---|---|
200 | อ่านหรือแก้ไขสำเร็จ | — |
201 | สร้างข้อมูลสำเร็จ | เก็บ id ที่คืนมา |
204 | ลบสำเร็จ | ไม่มีข้อมูลให้อ่าน |
400 | payload ไม่ผ่านการตรวจสอบ หรือการดำเนินการนั้นทำกับเอกสารนี้ไม่ได้ | แก้ payload และดู errorValidation |
401 | ไม่มีคีย์ คีย์ผิดรูปแบบ ถูกเพิกถอน หรือหมดอายุ | ดูการยืนยันตัวตน |
403 | องค์กรของคีย์นี้ไม่มีสิทธิ์ทำรายการนี้ | ตรวจว่าคีย์เป็นขององค์กรที่ถูกต้อง |
404 | ไม่พบข้อมูล หรือข้อมูลไม่ได้อยู่ในองค์กรนี้ | อย่าตีความว่า "ถูกลบแล้ว" อาจไม่เคยเป็นข้อมูลของคุณเลย |
409 | ข้อมูลขัดแย้ง เช่น ลบสิ่งที่ยังถูกอ้างอิงอยู่ | จัดการการอ้างอิงนั้นก่อน |
429 | เรียกถี่เกินโควตา | รอตามค่า Retry-After |
500 | ข้อผิดพลาดฝั่งเซิร์ฟเวอร์ | งานอ่าน retry ได้ งานเขียนให้ตรวจก่อน (ดูหัวข้อ retry ในBase URL และการจำกัดอัตราการเรียก) |
ค่า errorCode ที่ควรจัดการเป็นกรณีเฉพาะ
InvalidStatusTransition— เปลี่ยนสถานะจากสถานะปัจจุบันของเอกสารนี้ไม่ได้ ดูข้อมูลอ้างอิงชนิดเอกสารJournalEntryImbalanced— ยอดเดบิตและเครดิตของรายการบัญชีไม่เท่ากันOpenAPIRateLimitExceeded— เรียกเกินโควตาต่อคีย์
การแบ่งหน้า
endpoint รายการทุกตัวรับพารามิเตอร์สองตัวเดียวกัน
| พารามิเตอร์ | ค่าเริ่มต้น | หมายเหตุ |
|---|---|---|
page | 1 | เริ่มนับจาก 1 |
limit | 20 | สูงสุด 100 ค่าที่มากกว่านั้นจะถูกลดลงมา ไม่ใช่ถูกปฏิเสธ |
และตอบกลับด้วย items พร้อมบล็อก pagination
{
"items": [ { "id": 41 }, { "id": 40 } ],
"pagination": {
"previousPage": null,
"currentPage": 1,
"nextPage": 2,
"totalPages": 10,
"totalRows": 195
}
}previousPageและnextPageเป็นnullเมื่อถึงต้นหรือปลายช่วง นี่คือสัญญาณให้หยุด และตรวจง่ายกว่าการเทียบcurrentPageกับtotalPagestotalRowsคือจำนวนรวมทุกหน้า ไม่ใช่จำนวนในหน้านี้- โปรดจำว่าสินค้า เอกสารซื้อ เรื่องเบิกค่าใช้จ่าย และรายการบัญชี จะซ้อนทั้งก้อนนี้ไว้ใน
dataขณะที่ผู้ติดต่อและเอกสารขายคืนที่ระดับบนสุด
วนอ่านทุกหน้า
page=1
while [ -n "$page" ] && [ "$page" != "null" ]; do
body=$(curl -sS "$ABSERP_API_URL/openapi/v1/sales/documents?type=IV&limit=100&page=$page" \
-H "Authorization: Bearer $ABSERP_API_KEY")
echo "$body" | jq -c '.items[]'
page=$(echo "$body" | jq -r '.pagination.nextPage')
doneสองเรื่องที่ควรระวังเวลาวนอ่าน
- ใช้ขนาดหน้าที่ใหญ่ที่สุดที่ระบบคุณรับได้ (
limit=100) จำนวน request ที่น้อยลงหมายถึงโควตาที่ใช้ไปน้อยลง - ข้อมูลอาจเปลี่ยนระหว่างที่อ่านแต่ละหน้า สำหรับงาน export กลางคืน ให้กรองด้วยช่วงวันที่ปิดแล้ว (
fromDate/toDate) เพื่อไม่ให้ข้อมูลใหม่ดันแถวไปอยู่ในหน้าที่คุณอ่านผ่านไปแล้ว
สอง endpoint ที่ไม่แบ่งหน้า
GET /chart-of-accounts และ GET /warehouses คืนอาร์เรย์ธรรมดา เพราะเป็นรายการขนาดเล็กและมีจำนวนจำกัด ทั้งสองจะไม่สนใจ page และ limit
ขั้นตอนถัดไป
อ่านต่อที่ เอกสารขาย