custom error class

Custom Error Class JavaScript

วิธีเขียนโค้ด Handle Error ในภาษา JavaScript ขึ้นมาใช้เอง เพื่อให้มันแสดงรายละเอียดของ Error ได้ชัดเจนขึ้น หรือด้วยคำพูดที่เราต้องการสื่อสารกับ User โดยใช้ ES6 Custom Error Class

สร้างไฟล์ Utility

ที่โฟลเดอร์ราก (Project root) สร้างโฟลเดอร์ชื่อว่า util และสร้างไฟล์ 2 ไฟล์

  1. error.js
  2. และไฟล์ errorResponse.js

ด้วยคำสั่ง

take util && touch error.js errorResponse.js

จะได้โครงสร้างไฟล์ดังนี้ครับ

Error files
Error files

*** สามารถดูไฟล์เต็มได้ที่ github.com

อธิบาย Class ในภาษา JavaScript

ในไฟล์ errorResponse.js ให้คัดลอก เทมเพลตที่ใช้สร้างอ๊อบเจ็ค (Objects template creating) ที่ชื่อว่า Error หรือเราจะเรียกสั้นๆว่า Error Class นั่นเอง ด้วยคีย์เวิร์ด extends Error แล้วเปลี่ยนชื่อ Class ตามที่เราต้องการ ในที่นี้ขอใช้ชื่อว่า ErrorResponse (การตั้งชื่อ Class จะใช้ PascalCase)

class ErrorResponse extends Error {
  constructor(message, statusCode) {

    /** เรียกใช้งาน parent constructor ด้วย super ซึ่ง parent คือ Error Class นั่นเอง
    *   message เป็น Instance property ที่ถูกสร้างพร้อม Error Class
    */  ให้ดึงมาใช้โดยใส่ในเครื่องหมายวงเล็บเพื่อเป็น Input ตั้งต้น

    super(message);

    // statusCode ไม่ใช่ Instance property จึงใช้คีย์เวิร์ด this
    this.statusCode = statusCode;
  }
}

ใน Class จะมีฟังก์ชั่น constructor ซึ่งเราอาจเรียกว่า method

Method = Function ที่นั่งเป็นสมาชิกอยู่ใน Object (คุณใส่อะไรเข้าไปก็ได้ใน Object) เช่น

const obj = {

name: “foo bar”,

foo() { return ‘bar’; }

}

บางคนอาจจะแย้งว่า โครงสร้างของ Object มันเป็นแบบนี้นะ Key: Value (Key name ตามด้วย colon แล้วก็ Value)

const obj = {
  name: "Manot",
  foo: function() {
    // ...
  },
  bar: function() {
    // ...
  }
}

ทั้งนี้ตั้งแต่ JavaScript เวอร์ชั่น ES5 เราสามารถเขียนแบบ shorthand syntax ได้ดังนี้

const obj = {
  name: "Manot",
  foo() {
    // ...
  },
  bar() {
    // ...
  }
}

อธิบาย Class คร่าว ๆ แค่นี้ก่อนครับ

Error Handler

สำหรับไฟล์ error.js ให้เขียนโค้ดดังนี้

const ErrorResponse = require('./errorResponse');
const colors = require('colors');
colors.enable();

const errorHandler = (err, req, res, next) => {
  let error = { ...err };
  error.message = err.message;
  console.log(err.stack.red);

  if (err.name === 'CastError') {
    const message = "Source not found with id of " + err.value;
    error = new ErrorResponse(message, 404);
  }
  res.status(error.statusCode || 500).json({
    success: false,
    error: error.message || 'Server Error',
  });
};

module.exports = errorHandler; 
    

เมื่อสั่ง run โปรแกรม ด้วยคำสั่ง node server.js และลองใส่ข้อมูลแบบผิดๆจะได้ Error Response ตามนี้ครับ

Error Handler Response
Error Handler Response

ทีนี้เราต้องการสื่อสารกับ User มากกว่านี้ครับ เราก็สามารถใส่ Input เพิ่มเข้าไปใน Constructor ได้

โดยผมต้องการเพิ่ม เหตุผล ของ Error นี้เข้าไปด้วย ผมก็จะเขียน Constructor ดังนี้

constructor(message, statusCode, reason) {
  // Instance property
  super(message);

  // สร้าง property เพิ่ม
  this.statusCode = statusCode;

  // สร้าง property เพิ่ม
  this.reason = reason;

  // สร้าง property เพิ่ม แต่ไม่ต้องมี Input เพราะเรา Hard code เข้าไป
  this.name = 'ErrorResponse';
}

ก็จะได้ไฟล์ errorResponse.js ดังนี้

ไฟล์ errorResponse

สำหรับโค้ดบรรทัดที่ 6 จริง ๆ แล้ว this.name มันมีค่า Default เป็น Error นะครับ ถ้าเราไม่ได้ระบุชื่อ มันจะดึงค่า Default มาแสดงผลแบบนี้ครับ

Default of Error name
Default of Error name

เมื่อเท็มเพลตเปลี่ยน (ErrorResponse class) ไปตามที่เราต้องการแล้ว เราก็นำไปใช้ได้เลยครับ โดยแก้ไฟล์ error.js ให้เป็นดังนี้ครับ

ไฟล์ error.js

Error Stack

ในบรรทัดที่ 10 มีคีย์เวิร์ดที่น่าสนใจคือ err.stack มันเป็นรายละเอียดของ Error นั่นเอง ซึ่งมันจะอยู่รวมกันเป็น String ก้อนใหญ่ก้อนหนึ่ง มันจึงถูกเรียกว่า Error Stack ผมจะอธิบายเพิ่มเติมในบทความถัดไปครับ

ขออธิบายโค้ดบรรทัดที่ 16 นิดหนึ่งครับ ถ้าเรา console.log(reason) ออกมาดู มันมีข้อความแบบนี้ครับ

Error: ” ข้อความ”

Error Reason
Error Reason

ผมไม่ต้องการคำว่า Error และ white space ผมกำจัดมันออกด้วยฟังก์ชั่นสำเร็จรูปของ JavaScript ทีละขั้นตอน ดังนี้ครับ

// ค่าตัวแปร.split(); เพื่อแยก String ออกจากกัน
// ในกรณีนี้แยก String ณ จุดที่มีเครื่องหมายโคลอน
reason.split(':');

// expected output: "Error", " ข้อความ"

Array

เมื่อผมใช้คำสั่ง split() แยก String ผมจะได้ output ออกมาเป็น Array ตามรูปนี้ครับ

split function output
split() output

Array เป็น Object ชนิดหนึ่ง ที่มันถูกเรียกให้ต่างออกไปเพราะมันไม่มี Key Name มันมีแต่ Value

เราลองนึกภาพดูเรามี String อยู่ก้อนหนึ่ง เราจับมันมาแยกออกเป็น 2 ก้อน หลังจากแยกออกมาแล้ว สิ่งที่มันได้รับคือ “ลำดับที่” เราก็ใช้ลำดับที่นั่นแหละครับเป็น Key Name ให้มัน แบบนี้นะครับ

Object ทั่วไป { Key Name: Value }

Array [ Order: Value ]


สมาชิก Array ตัวที่ 2 ซึ่งเป็นข้อความที่ผมต้องการนำมาใช้ โดย Array จะเริ่มนับสมาชิกตัวแรกที่เลข 0 ดังนั้นเมื่อมันเป็นสมาชิกตัวที่ 2 มันจึงได้หมายเลข 1 นะครับ ผมระบุแบบนี้

reason.split(':')[1]

// expected output: " ข้อความ"

จะเห็นว่ามันมี white space (วรรค) ติดมาด้วย ผมสามารถกำจัดมันด้วยฟังก์ชั่น trim(); โดย

reason.split(':')[1].trim();

// expected output: "ข้อความ"

โดย trim() จะตัด white space หน้าสุด และหลังสุดของข้อความทิ้งไปครับ เมื่อมาถึงตรงนี้เราจะได้ output ตามรูป

trim function output
trim() output

เมื่อได้ข้อความในรูปแบบที่ต้องการแล้ว ก็นำไปใช้ได้เลยครับตามโค้ดในบรรทัดที่ 19 ของไฟล์ error.js เราก็จะได้ Error Handler ตามรูปนี้ครับ

Error Handler Final Output
Error Handler Final Output

สรุป

การสร้าง Custom Error Class ในภาษา JavaScript จะสร้างโดยการนำเท็มเพลต Error Class มาใช้ หรือเรียกว่า Sub classing ด้วยคีย์เวิร์ด extends โดยมีรูปแบบ

class <ชื่อที่ต้องการ> extends Error {
  constructor(message, ...ค่าอื่นๆเพิ่มเติมตามชอบ) {
    super(message);
    this.ค่าอื่นๆ = ค่าอื่นๆ;
  }
}

module.exports = <ชื่อที่ต้องการ> 

และนำไปใช้งานโดย export ออกไปด้วยคำสั่ง module.exports = <ชื่อที่ต้องการ>

เอกสารอ้างอิง

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error

https://www.javascripttutorial.net/javascript-string-trim/

https://stackoverflow.com/questions/96428/how-do-i-split-a-string-breaking-at-a-particular-character

https://javascript.info/object

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super

https://www.robinwieruch.de/javascript-naming-conventions

Github repo

0 0 votes
ให้คะแนนบทความ
Notify of
guest
0 ความเห็นทั้งหมด
Inline Feedbacks
ดูความเห็นทั้งหมด
0
แสดงความเห็นได้นะx
()
x
Scroll to Top