🔵 Node.js

วิธีทำ Request Validation ด้วย Zod และจัดการ Error แบบรวมศูนย์ใน Node.js

10 นาที 19 views บันทึกเป็น PDF
วิธีทำ Request Validation ด้วย Zod และจัดการ Error แบบรวมศูนย์ใน Node.js

ไม่อยากให้ API พังเพราะข้อมูลจากผู้ใช้? มาเรียนรู้วิธีตรวจสอบข้อมูล (Validation) ด้วย Zod และทำระบบจัดการข้อผิดพลาด (Error Handling) แบบมือโปร

ทำไมต้องมีการตรวจสอบข้อมูลที่ส่งเข้ามา (Request Validation)

เวลาเราสร้าง API (ช่องทางสื่อสารระหว่างโปรแกรม) ขึ้นมาสักตัว เรามักจะเปิดรับข้อมูลจากผู้ใช้งานผ่านทาง Request Body (ส่วนของข้อมูลที่ส่งมาพร้อมกับคำขอ) ถ้าเราเชื่อใจข้อมูลเหล่านั้นมากเกินไปโดยไม่ตรวจสอบอะไรเลย โปรแกรมของเราอาจจะพังได้ง่ายๆ เหมือนกับร้านอาหารที่ยอมให้ลูกค้าสั่งเมนูอะไรก็ได้ที่ไม่มีในร้าน ซึ่งจะทำให้พ่อครัวงงและทำอาหารออกมาไม่ได้

การทำ Request Validation (ขั้นตอนการตรวจสอบความถูกต้องของข้อมูล) จึงเปรียบเสมือนพนักงานต้อนรับที่คอยเช็กว่า ข้อมูลที่ส่งมานั้นครบถ้วนและถูกต้องตามรูปแบบที่เราต้องการหรือไม่ เช่น ถ้าเราต้องการให้ผู้ใช้สมัครสมาชิก เราก็ต้องเช็กว่าเขาใส่ชื่อและอีเมลมาครบไหม หรืออีเมลมีรูปแบบที่ถูกต้องหรือเปล่า การป้องกันตั้งแต่ด่านแรกนี้จะช่วยลดภาระของฐานข้อมูลและป้องกันบั๊ก (ข้อผิดพลาดของโปรแกรม) ที่อาจเกิดขึ้นในอนาคต

หัวใจสำคัญ ของการพัฒนาซอฟต์แวร์ที่ดีคือการไม่ไว้ใจข้อมูลจากภายนอก 100% การทำระบบตรวจสอบที่ดีจะช่วยให้เราเขียนโค้ดได้มั่นใจขึ้น เพราะเราสามารถการันตีได้ว่าข้อมูลที่ผ่านด่านตรวจสอบเข้ามานั้นสะอาดและพร้อมใช้งานเสมอ ไม่ต้องไปเขียนโค้ดดักเช็กเงื่อนไขซ้ำซ้อนในทุกๆ ส่วนของโปรแกรมอีกต่อไป

รู้จักกับ Zod เครื่องมือช่วยเช็กข้อมูลให้ง่ายขึ้น

Zod (ไลบรารีสำหรับกำหนดโครงสร้างข้อมูลและตรวจสอบความถูกต้อง) เป็นเครื่องมือที่ได้รับความนิยมมากในปัจจุบัน เพราะมันช่วยให้เราประกาศโครงสร้างข้อมูลได้อย่างชัดเจนและเข้าใจง่ายเหมือนการเขียนภาษาอังกฤษทั่วไป แถมยังทำงานร่วมกับ TypeScript (ภาษาที่เพิ่มระบบตรวจสอบชนิดข้อมูลให้ JavaScript) ได้ดีเยี่ยม ทำให้เราเห็นคำแนะนำขณะเขียนโค้ดได้ทันที

ลองนึกภาพว่าเราต้องการสร้างระบบสมัครสมาชิก เราต้องกำหนดว่าชื่อต้องเป็นข้อความและอีเมลต้องเป็นรูปแบบอีเมลจริง แทนที่จะเขียนโค้ดดักเงื่อนไขยาวเหยียด เราสามารถใช้ Zod Schema (คำจำกัดความของรูปแบบข้อมูล) มากำหนดกฎเกณฑ์ได้เลย ซึ่งช่วยลดความซับซ้อนของโค้ดลงไปได้มหาศาลสำหรับมือใหม่ที่ยังไม่คุ้นเคยกับการเขียนเงื่อนไขที่ซับซ้อน

การใช้เครื่องมืออย่าง Zod ไม่ได้แค่ช่วยให้งานเร็วขึ้น แต่ยังช่วยให้โค้ดของเราอ่านง่ายขึ้นมาก ถ้าวันหนึ่งเราต้องการเปลี่ยนกฎ เช่น เพิ่มจำนวนตัวอักษรขั้นต่ำของชื่อ เราก็แค่แก้ที่ Schema บรรทัดเดียว ทุกอย่างก็จะอัปเดตตามทันทีโดยไม่ต้องไปไล่แก้โค้ดในทุกฟังก์ชันที่เรียกใช้ข้อมูลนั้น

const { z } = require("zod");

// กำหนดกฎว่าต้องมีชื่อและอีเมล
const userSchema = z.object({
  name: z.string().min(1, "ชื่อต้องไม่ว่างเปล่า"),
  email: z.string().email("รูปแบบอีเมลไม่ถูกต้อง"),
});

// ข้อมูลสมมติที่ส่งเข้ามา
const userData = { name: "Somchai", email: "invalid-email" };

// ตรวจสอบข้อมูล
const result = userSchema.safeParse(userData);

if (!result.success) {
  console.log(result.error.format()); // แสดงข้อผิดพลาด
}

ในตัวอย่างนี้ เรานำเข้า z จาก Zod เพื่อสร้างกฎ userSchema ขึ้นมา โดยกำหนดให้ name เป็นข้อความและ email ต้องเป็นอีเมลที่ถูกต้อง จากนั้นเราใช้ safeParse เพื่อเช็กข้อมูล ถ้าข้อมูลไม่ถูกต้อง result.success จะเป็น false และเราจะเห็นรายละเอียดข้อผิดพลาดผ่าน result.error.format()

ผลลัพธ์ที่ได้จากการรันโค้ดข้างต้นคือข้อความแจ้งเตือนข้อผิดพลาดที่ระบุว่าอีเมลไม่ถูกต้องตามรูปแบบ ซึ่งช่วยให้เราสามารถส่งข้อความนี้กลับไปบอกผู้ใช้งานได้ทันทีว่าพวกเขาทำอะไรผิดพลาดไปบ้าง

การทำ Centralized Error Handling Middleware

เมื่อเราตรวจสอบข้อมูลแล้วพบว่าไม่ผ่าน เราต้องส่งคำตอบกลับไปหาผู้ใช้ แต่ถ้าเราเขียนโค้ดส่งข้อความผิดพลาดแยกไปในทุกๆ ฟังก์ชัน จะทำให้โค้ดรกและจัดการยากมาก Centralized Error Handling (การรวมจุดจัดการข้อผิดพลาดไว้ที่เดียว) จึงเป็นแนวทางที่ดีที่สุด เพราะเราสามารถกำหนดรูปแบบการตอบกลับให้เป็นมาตรฐานเดียวกันทั้งระบบ

ใน Node.js เราสามารถใช้ Middleware (ฟังก์ชันที่คั่นกลางระหว่างการรับ Request และการส่ง Response) เพื่อดักจับทุกข้อผิดพลาดที่เกิดขึ้นในโปรแกรม ถ้ามีอะไรผิดพลาดเกิดขึ้น เราแค่สั่ง next(error) โปรแกรมจะส่งต่อข้อผิดพลาดนั้นมายังจุดจัดการหลักที่เราวางไว้เพียงจุดเดียว ทำให้โค้ดในส่วนอื่นสะอาดและโฟกัสแค่การทำงานหลักของมันเท่านั้น

วิธีนี้มีข้อดีคือ ถ้าเราอยากเปลี่ยนรูปแบบการแจ้งเตือน เช่น อยากเพิ่มรหัสข้อผิดพลาดหรือเปลี่ยนภาษาของข้อความ เราก็แค่มาแก้ที่จุดเดียวใน Error Middleware (ฟังก์ชันจัดการข้อผิดพลาด) ไม่ต้องไปไล่แก้ทุกไฟล์ในโปรเจกต์ ซึ่งถือเป็นวินัยที่ดีของโปรแกรมเมอร์มืออาชีพที่ช่วยประหยัดเวลาในการบำรุงรักษาโค้ดในระยะยาว

// ตัวอย่าง Error Middleware
app.use((err, req, res, next) => {
  console.error(err.message); // พิมพ์ข้อผิดพลาดลงใน Console
  res.status(400).json({
    status: "error",
    message: err.message,
  });
});

โค้ดนี้คือฟังก์ชันที่รับพารามิเตอร์ 4 ตัว ซึ่งเป็นรูปแบบเฉพาะของ Middleware ใน Express โดย err คือข้อผิดพลาดที่ส่งมา เราใช้ res.status(400) เพื่อบอกว่าคำขอนี้ผิดพลาด และส่งข้อมูลกลับไปเป็น JSON (รูปแบบข้อมูลที่นิยมใช้ส่งผ่านเว็บ) เพื่อให้ฝั่งผู้ใช้งานนำไปแสดงผลต่อได้

เมื่อรันจริง หากมีฟังก์ชันใดในโปรแกรมเรียกใช้ next(new Error("ข้อมูลไม่ครบ")) ระบบจะมาทำงานในบล็อกนี้และส่งข้อความ {"status": "error", "message": "ข้อมูลไม่ครบ"} กลับไปที่ผู้ใช้ทันที

เปรียบเทียบระหว่าง Zod และ Joi

หลายคนอาจเคยได้ยินชื่อ Joi (ไลบรารีตรวจสอบข้อมูลรุ่นพี่) มาก่อน ซึ่งมีหน้าที่คล้ายกับ Zod มาก ทั้งสองตัวช่วยตรวจสอบข้อมูลได้ดีเยี่ยม แต่ความแตกต่างที่สำคัญคือ Zod ถูกออกแบบมาเพื่อทำงานกับ TypeScript ได้ดีกว่าตั้งแต่ต้น ทำให้เราไม่ต้องเขียนโค้ดนิยามข้อมูลซ้ำซ้อนสองรอบ ทั้งรูปแบบข้อมูลและชนิดของข้อมูล

สำหรับมือใหม่ ถ้าคุณเพิ่งเริ่มเรียนรู้ Joi ก็ยังเป็นตัวเลือกที่ดีเพราะมีเอกสารประกอบที่อ่านง่ายและใช้งานแพร่หลายในโปรเจกต์เก่าๆ แต่ถ้าคุณกำลังเริ่มโปรเจกต์ใหม่และอยากฝึกใช้เครื่องมือที่ทันสมัย Zod จะเป็นตัวเลือกที่คุ้มค่ากว่าในการลงทุนเรียนรู้ เพราะมันเป็นมาตรฐานใหม่ที่หลายบริษัทเลือกใช้ในปัจจุบัน

ไม่ว่าคุณจะเลือกตัวไหน สิ่งสำคัญไม่ใช่แค่การเลือกเครื่องมือให้ถูก แต่คือการเข้าใจว่า ทำไม เราต้องตรวจสอบข้อมูล หากคุณเข้าใจหลักการพื้นฐานแล้ว การเปลี่ยนไปใช้เครื่องมือตัวอื่นก็จะเป็นเรื่องง่ายมาก เพราะตรรกะในการทำงานของมันเหมือนกันแทบทั้งหมด คือการกำหนดกฎและเช็กข้อมูลที่ได้รับมา

ข้อควรระวังสำหรับมือใหม่

จุดที่มือใหม่มักพลาดบ่อยคือการลืมตรวจสอบข้อมูลในทุกๆ จุดที่รับค่าเข้ามา หรือตรวจสอบแบบไม่รอบคอบ เช่น การลืมเช็กว่าค่าที่ส่งมาเป็นค่าว่างหรือไม่ ทำให้เกิดข้อผิดพลาดแบบ undefined (ค่าที่ยังไม่ได้กำหนด) ในโปรแกรมจนแอปพังได้ง่ายๆ ดังนั้นต้องฝึกให้เป็นนิสัยว่าทุกครั้งที่เห็น req.body ต้องมีขั้นตอนตรวจสอบเสมอ

อีกเรื่องคือการแสดงข้อมูลข้อผิดพลาดมากเกินไป บางครั้งเราเผลอส่งรายละเอียดระบบ เช่น ชื่อไฟล์หรือชื่อฟังก์ชันที่ผิดพลาดกลับไปให้ผู้ใช้ ซึ่งเป็นช่องโหว่ทางความปลอดภัย (Security Risk) ที่แฮกเกอร์อาจใช้ประโยชน์ได้ ควรแสดงแค่ข้อความที่จำเป็นและเข้าใจง่ายสำหรับผู้ใช้ทั่วไปก็พอ ส่วนรายละเอียดเชิงลึกให้เก็บไว้ใน Log (บันทึกการทำงานของระบบ) บนเซิร์ฟเวอร์แทน

การฝึกเขียน Validation (การตรวจสอบข้อมูล) ให้เป็นส่วนหนึ่งของขั้นตอนการพัฒนา จะทำให้คุณกลายเป็นโปรแกรมเมอร์ที่เขียนโค้ดได้รัดกุมและมีความรับผิดชอบต่อคุณภาพของซอฟต์แวร์มากขึ้น เริ่มต้นจากการตรวจสอบง่ายๆ แล้วค่อยๆ ขยับไปใช้ระบบที่ซับซ้อนขึ้นเมื่อคุณเริ่มมีความชำนาญมากขึ้นครับ

สรุป

การตรวจสอบข้อมูลด้วย Zod และการทำ Centralized Error Handling คือหัวใจสำคัญของการเขียน Backend ที่มีคุณภาพ มันช่วยให้โค้ดของคุณสะอาด ปลอดภัย และดูแลรักษาง่ายขึ้นมาก ไม่ว่าจะเป็นโปรเจกต์เล็กๆ หรือระบบขนาดใหญ่ การวางโครงสร้างเหล่านี้ไว้ตั้งแต่ต้นจะช่วยลดจำนวนบั๊กที่คุณต้องตามแก้ในอนาคตได้อย่างมหาศาล

ลองนำความรู้ในบทความนี้ไปใช้กับโปรเจกต์ของคุณดูครับ เช่น ถ้าคุณกำลังทำระบบ "สมุดจดบันทึก" ให้ลองเพิ่มการตรวจสอบว่าหัวข้อบันทึกต้องไม่ว่าง และถ้าบันทึกไม่สำเร็จให้ส่งข้อความเตือนกลับไปหาผู้ใช้ผ่านระบบจัดการข้อผิดพลาดที่เราสร้างขึ้น เพียงเท่านี้คุณก็จะเห็นภาพการทำงานของระบบที่ดูเป็นมืออาชีพมากขึ้นแล้ว

จงจำไว้ว่าโปรแกรมเมอร์ที่เก่งไม่ได้วัดกันที่เขียนโค้ดเร็วแค่ไหน แต่อยู่ที่การเขียนโค้ดที่รัดกุมและจัดการกับปัญหาได้อย่างเป็นระบบ การฝึกฝนทำสิ่งเหล่านี้ให้เป็นนิสัยจะทำให้คุณก้าวข้ามจากมือใหม่ไปสู่ระดับที่ทีมงานไว้วางใจได้อย่างแน่นอนครับ

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

คู่มือการทำ Production Deployment: รันโปรเจกต์ด้วย PM2 และ Docker ให้เสถียรเหมือนมือโปร
Node.js

คู่มือการทำ Production Deployment: รันโปรเจกต์ด้วย PM2 และ Docker ให้เสถียรเหมือนมือโปร

เรียนรู้วิธีนำโปรเจกต์ขึ้นเซิร์ฟเวอร์จริงให้รันได้ 24 ชั่วโมงด้วย PM2 และใช้ Docker ช่วยคุมสภาพแวดล้อมให้เหมือนกันทุกเครื่อง ลดปัญหาโค้ดพังเมื่อย้ายที่

1 week ago 11 นาที
15 views
เปลี่ยนโปรเจกต์ Node.js เป็น TypeScript: วิธีตั้งค่าและใช้งานสำหรับมือใหม่
Node.js

เปลี่ยนโปรเจกต์ Node.js เป็น TypeScript: วิธีตั้งค่าและใช้งานสำหรับมือใหม่

อยากเปลี่ยนจาก Node.js มาใช้ TypeScript แต่ไม่รู้เริ่มยังไง? บทความนี้สอนตั้งค่า tsconfig.json, การรันด้วย tsx และการทำ Type Checking ให้ Express แบบเข้าใจง่าย

1 week ago 9 นาที
12 views
สอนเขียน Automated Testing ด้วย Jest และ Supertest สำหรับมือใหม่
Node.js

สอนเขียน Automated Testing ด้วย Jest และ Supertest สำหรับมือใหม่

เลิกทดสอบโค้ดด้วยมือแบบเดิม ๆ มาหัดเขียน Automated Testing ด้วย Jest และ Supertest เพื่อเช็กฟังก์ชันและ API ให้ทำงานถูกต้องแม่นยำ ลดบั๊กกวนใจ

1 week ago 9 นาที
15 views