Error handling in Express / Node.js
สวัสดีครับ วันนี้จะมาเขียนสั้นๆเกี่ยวกับการจัดการ Error ด้วย Node.js และ Express
code: https://github.com/pongsakornsemsuwan/express-error-handling-sample
เริ่มจากขึ้น express ง่ายๆมาตัวนึงครับ โดยมีแค่ function สำหรับจัดการ voucher กับตัว errorHandler ครับ
ตัว errorHandler
ซึ่งเป็น error handling middleware จะต่างจาก middleware ปกติตรงที่มี argument 4 ตัวครับ ซึ่งในทีนี้เราจะแยกไปเขียนใน errorHandler.js
เพื่อความเป็นระเบียบ
แยกระหว่าง Business Error กับ Application Error
ก่อนอื่นเราต้องแยกก่อนว่า Error ที่กำลังเกิดขึ้นนั้น สาเหตุมาจากการใช้งานที่ผิดพลาดของ User หรือเป็น Error จากระบบเราจริงๆ ในกรณีนี้ เราจะใช้ Journey ของการตรวจสอบ Voucher มาเป็นเหตุการณ์สมมตินะครับ
Business Error อาจจะเป็นการที่ User กรอก voucher code ที่หมดอายุไปแล้ว หรือไม่มีอยู่ ซึ่งเราจะรู้ล่วงหน้าอยู่แล้วและต้องมีการรองรับ และตอบกลับไปหน้าบ้านให้แสดงผล
Application Error อาจจะเป็นการที่ User กรอก voucher code เป็น format ที่เราไม่ได้รองรับมา แล้วเราไม่ได้เขียนดักไว้ ทำให้มี Error ระเบิดตอนใช้งานจริง ในกรณีนี้เราอาจจะ return Unexpected Error ออกไป เป็น Generic Error ครับ เนื่องจากปกติแล้ว เราจะไม่ควรเปิดเผยข้อมูลการพังที่หลังบ้านเราไปให้หน้าบ้านรู้นะ
จะเห็นว่าวิธีการรับมือกับ Error สองประเภทนี้นั้นต่างกัน เพราะฉะนั้นแนะนำให้แยกสองอย่างนี้ออกจากกันครับ
จากตัวอย่าง เราจะมี error ทั้งหมด 3 ตัว
1. เมื่อใส่ code = 0 จะได้ว่า code หมดอายุไปแล้ว (business error)
2. เมื่อใส่ code = -1 จะได้ว่า code ผิด (business error)
3. เมื่อใส่ code เป็นอะไรก็ได้ที่ไม่ใช่ตัวเลข จะแทนกรณีที่เกิด error ที่เราไม่ได้ handle ครับ
ในโค้ดตัวอย่างจะเห็นว่าเราใช้ next
ซึ่งเป็นการส่ง request ไปให้ middleware ตัวถัดไปจัดการต่อครับ โดยถ้ามี parameter ส่งเข้าไปใน next
ด้วย request จะถูกส่งไปให้ error handling middleware ครับ (พวกที่มี 4 argument)
ตัดสินใจว่าจะใช้ Http Code หรือ Custom Error Code
เป็นที่ถกเถียงกันว่า เราควรจะใช้ Http Code เพื่อช่วยบอกความหมายของ response เลย (เช่น ถ้าหา voucher ไม่เจอ ให้เป็น 404 ไปเลย) หรือเก็บไว้ใช้ในระดับ network level ส่วนตัวผมอยู่ทีม เก็บ http code ไว้ใช้ที่ระดับ network level และใช้ custom error code เพื่อ represent business error ครับ แต่ในทีนี้จะทำให้ดูทั้งสองแบบเผื่อเอาไปปรับใช้นะครับ
Custom Error Code
ด้านบนจะเป็นการใช้ custom error code ที่ถูกส่งเข้ามาตอนสร้าง Error ครับ
สำหรับตัว error handler จะมีการดูว่าเป็น business error หรือเปล่า ถ้าใช่เราจะใส่ status ให้เป็น 200 แล้วใส่ customer error message ไปครับ
กรณีที่ไม่ใช่ business error เราจะใส่เป็น 500 และกำหนด message ไปแทนที่จะใช้ตัว error ดั้งเดิมเพื่อกันไม่ให้ error message ถูกส่งไปถึงหน้าบ้านครับ
Test
เมื่อเรายิง code =0 หรือ -1 จะได้ 200OK แต่มี errorCode ตามที่เซตไว้ครับ
กรณียิง code = xx จะได้ 500 Internal Server Error
HTTP Code
ในกรณีที่เราอยากใช้ http code ไปเลยก็แค่เปลี่ยนตัว BusinessError ของเราให้รับ httpCode แทน errorCode และแก้ errorHandler ให้ใส่ httpCode ไปใน response header (res.status) แทนครับ
นอกจากนี้เรายังสามารถ refactor ตัว BusinessError ต่อให้ฟิกค่า http ไปสำหรับแต่ละ Error ไปเลย เช่น
หวังว่าพอจะได้ไอเดียไปปรับใช้กันนะครับ