

เวลาเขียนเรียก API ด้วย fetch เรามักครอบด้วย try catch แล้วให้หน้าจอแสดงข้อความเมื่อเกิดปัญหา แต่ในกรณี server ตอบ404 โค้ดอาจยังเดินต่อในทางปกติ จึงอาจเข้าใจว่ามันไม่ได้ตรวจข้อผิดพลาดให้หรือคำขอมีอะไรผิด
จุดที่ต้องแยกคือ fetch รับผิดชอบการได้ Response ตามกลไกการเรียก ส่วนรหัส HTTP บอกผลของคำขอในระดับบริการ และการอ่าน body ก็เป็นงานอีกขั้นหนึ่ง การมี catch จึงไม่ได้ทำให้ทั้งสามชั้นใช้ความหมายสำเร็จเหมือนกันเอง
ถ้าแยกขั้นเหล่านี้ชัด เราจะเลือกข้อความกับทางทำต่อได้เหมาะกว่าแสดงว่าเน็ตเสียกับทุกกรณีครับ โดยเฉพาะคำขอที่อาจสร้างผลไปแล้วก่อนคำตอบขาด
Promise ที่ fetch คืนไม่ได้ reject เพียงเพราะ server ตอบสถานะอย่าง404หรือ500 แต่จะได้ Response ให้เราตรวจ status ต่อ ส่วนปัญหาบางชนิดในการเรียก เช่น network error อาจทำให้ Promise reject ตามกลไกของ browser
Response.ok เป็นตัวช่วยบอกว่า status อยู่ในช่วง200ถึง299 ไม่ใช่การยืนยันว่าข้อมูลตรง schema หรือกระบวนการธุรกิจเสร็จครบ เช่น202อาจเป็นการรับงานไว้รอประมวลผลตามสัญญา ไม่ใช่ไฟล์รายงานพร้อมดาวน์โหลดแล้ว
จึงควรตัดสินทางจัดการจากสถานะกับข้อตกลงของ endpoint นั้น ไม่เอาการที่ await fetch ผ่านมาได้ไปใช้เปิดหน้าสำเร็จทันที และไม่บังคับให้ทุกสถานะนอก200ถูกเรียกว่าการเชื่อมต่อขาดเหมือนกันทั้งหมด

ตัวอย่างต่อไปนี้เป็น API สมมติที่ตกลงว่า response สำเร็จแบบอื่นส่ง JSON และ204ไม่มี body จึงใช้โครงแบบนี้ได้ ส่วนระบบจริงต้องอ่านสัญญาของ endpoint ที่เรียก ไม่คัดลอกเงื่อนไขไปครอบทุกบริการโดยไม่ดูรูปแบบข้อมูล
const response = await fetch("/api/example");
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const result = response.status === 204
? null
: await response.json();
การ throw ในตัวอย่างทำให้โค้ดภายนอกเลือกใช้ catch จัดการ HTTP ที่ไม่ผ่านได้ แต่เป็นกติกาที่เราเพิ่มขึ้น ไม่ใช่ fetch เปลี่ยนรหัส HTTP ทุกแบบเป็น exception ให้เอง ข้อความจริงสำหรับผู้ใช้ก็ควรมาจากสิ่งที่แก้หรือทำต่อได้ตามนโยบาย ไม่จำเป็นต้องแสดงเลขสถานะเพียงตัวเดียว
หาก error response มีข้อมูลแบบที่บริการกำหนด เช่น ชื่อช่องที่ต้องแก้ ก็ควรอ่านตามรูปแบบนั้นอย่างระมัดระวัง ไม่ส่ง stack trace หรือข้อความภายในทุกอย่างไปแสดงเพียงเพราะมันอยู่ใน body ที่อ่านได้
เมื่อได้รับ status กับ headers fetch อาจคืน Response มาแล้วก่อนอ่าน body ครบ การเรียก json หรือ text จึงเป็นงาน asynchronous อีกขั้นที่ยังอาจผิดพลาด เช่น ข้อมูลขาดหรือไม่ตรงกับรูปแบบที่พยายามอ่าน
ถ้า API ที่คาดว่าเป็น JSON กลับได้หน้า HTML จาก proxy หรือหน้า login การ parse ไม่ผ่านก็ไม่ได้ยืนยันว่าฐานข้อมูลเสีย ต้องตรวจ URL สุดท้าย status และ Content-Type ร่วมกับเส้นทางที่ตอบ ไม่เดาจากข้อความ parser อย่างเดียว
แม้แปลง JSON ผ่าน ก็ยังต้องตรวจว่ามี field กับชนิดค่าตามที่ใช้จริง ตัวอย่าง object ที่มี status เป็นข้อความคนละชุดอาจผ่าน JSON parser แต่ไม่ผ่านสัญญางาน ความถูกต้องของไวยากรณ์จึงเป็นเพียงชั้นหนึ่งของการใช้ข้อมูล

คำขอที่ข้อมูลไม่ครบอาจต้องให้คนแก้ฟอร์ม ส่วนสิทธิ์ไม่พออาจต้องยืนยันตัวตนหรือแสดงขอบเขตที่ทำได้ และบริการไม่พร้อมอาจต้องรอหรือตามสถานะเดิม การแสดงข้อความเดียวว่าลองใหม่ให้ทุกกรณีจะไม่ช่วยให้แก้ต้นเหตุได้
สำหรับปัญหาระดับ network หรือ CORS โค้ดหน้าเว็บอาจไม่ได้เห็น response รายละเอียดเหมือนฝั่ง server จึงควรตรวจจาก Network และหลักฐานของบริการในสภาพทดสอบ ไม่ตีความว่าการอ่าน status ไม่ได้เท่ากับ server ไม่เคยรับคำขอ
ข้อมูลสำหรับตามปัญหา เช่น รหัสการเรียกที่เปิดเผยได้ ช่วยเชื่อมอาการกับฝั่งบริการโดยไม่ต้องพิมพ์ token หรือข้อมูลส่วนตัวทั้งหมด ควรเก็บรายละเอียดภายในสำหรับผู้ดูแลตามสิทธิ์ และให้หน้าจอมีข้อความที่สัมพันธ์กับงานของคนใช้
AbortController ใช้ส่ง signal เพื่อยกเลิกการรอหรืออ่านตามกลไก fetch ได้ และการยกเลิกอาจเกิดหลังได้รับ Response แต่ก่อนอ่าน body เสร็จ จึงต้องรู้ว่าจังหวะที่ error เกิดไม่ได้จำเป็นต้องอยู่ก่อน server เริ่มงาน
ถ้าคำขอสร้างผลไปแล้ว การ abort ฝั่งหน้าเว็บไม่ทำให้ข้อมูลใน server ย้อนคืนเอง ก่อนเสนอให้กดใหม่จึงควรมีวิธีตรวจผลเดิมหรือใช้ตัวตนของคำสั่งตามที่ API รองรับ ไม่ถือว่าทุก exception หมายถึงยังไม่มีอะไรเกิดขึ้น
กรณีผู้ใช้เปลี่ยนหน้าหรือค้นคำใหม่ การเลิกอ่านคำขอเก่าช่วยจัดอายุงานฝั่งหน้าเว็บได้ แต่ยังควรป้องกันผลเก่าที่มาถึงช้ากว่าไปทับผลใหม่ตามการออกแบบของ state ไม่ให้การมี controller เพียงตัวเดียวแทนการจัดการคำขอหลายรอบทั้งหมด
ชุดทดลองควรมี HTTP ที่ไม่ผ่าน response ที่ไม่ใช่ JSON สถานะไม่มี body และการขาดระหว่างอ่าน พร้อมกรณี server ทำผลแล้วแต่ client ไม่เห็นคำตอบ ตรวจว่าหน้าจอคงข้อมูลที่คนกรอกและตามผลเดิมได้ตามสัญญา
หากมีการลองใหม่ ควรกำหนดจากชนิดคำขอกับความแน่นอนของผล ไม่ตั้ง retry ทุกครั้งที่เข้า catch โดยไม่แยกงานอ่านกับงานสร้างผล ส่วนตัวหมุนรอและข้อความสำเร็จก็ควรตามผลที่ตรวจถึงขั้นนั้นจริง ไม่ตามเพียงการจบฟังก์ชันโดยไม่มี exception
fetch แยกการได้ Response ออกจากผล HTTP และการอ่าน body เมื่อเราเพิ่มการตรวจ status รูปแบบและความหมายธุรกิจตามลำดับ จะจัดการปัญหาได้ตรงกว่าพึ่ง catch เพียงจุดเดียว ส่วนการยกเลิกหรือคำตอบขาดต้องรักษาความไม่แน่ใจของผลไว้ เพื่อให้คนใช้ทำต่อได้โดยไม่สร้างงานซ้ำเพราะหน้าจอรายงานผิดขั้น