Back to notes
mastery-backend-nestjs
Featured

NestJS Error Handling: Interceptors & Filters

ทำ API ให้ Standard: แปลง Response ทุกอันให้อยู่ในรูปแบบเดียวกัน และดักจับ Error ด้วย Exception Filters

January 29, 20262 min read readNNexis by Seereen

🛑 1. The Problem First: "คำตอบที่ไม่เคยซ้ำกัน" (Inconsistent API Response)

ลองนึกภาพว่าคุณเป็น Frontend ที่ต้องเชื่อมต่อกับ API 10 ตัว แต่ละตัวส่งคำตอบกลับมาคนละท่า:

HLJS JSON
// API 1: ส่งแค่ data
{ "id": 1, "name": "Joe" }

// API 2: ส่งห่อ data ไว้ข้างใน
{ "result": { "id": 2, "name": "Jane" } }

// API 3: เวลาพังส่ง Error เป็น String ธรรมดา
"User not found"

ปัญหา: การที่ API ไม่มีมาตรฐานทำให้ Frontend ต้องเขียนโค้ด if-else เช็คโครงสร้างทุุกครั้งที่ยิง API (Boilerplate มหาศาล) และเมื่อระบบมีขนาดใหญ่ขึ้น การไล่หาว่า Error เกิดขึ้นที่ไฟล์ไหนเวลาพังใน Production จะกลายเป็นเรื่องที่เป็นไปไม่ได้เลย นี่คือเหตุผลที่เราต้องมี "ตัวกลาง" ในการจัดระเบียบครับ


💡 2. Real-Life Analogy: พนักงานแพ็คของและประกันภัย (Packer & Insurance)

  • Interceptor: เหมือน "พนักงานแพ็คของท้ายสายพาน". ไม่ว่าเชฟจะทำอาหารอะไรมา (Data) พนักงานคนนี้จะเอาใส่กล่องแบรนด์บริษัทที่มีหน้าตาสวยงามและแปะป้ายวันผลิต (Timestamp) ก่อนส่งถึงลูกค้าเสมอ
  • Exception Filter: เหมือน "แผนกเคลมสินค้า". เมื่อเกิดอุบัติเหตุในร้าน (Code Crash) พนักงานคนนี้จะเข้ามาคุมสถานการณ์ ไม่ปล่อยให้ลูกค้าเห็นความวุ่นวายหลังบ้าน แต่จะยื่น "ใบเคลม" (Custom Error JSON) ที่ระบุชัดเจนว่าเกิดอะไรขึ้นและต้องทำยังไงต่อ
  • Logger: เหมือน "กล่องดำของเครื่องบิน". มันบันทึกทุุกการเคลื่อนไหวของระบบ เพื่อให้เวลาเครื่องตก (System Crash) เราสามารถเอาข้อมูลออกมาวิเคราะห์ได้ว่า "ใครคือจำเลย"

🚀 3. Execution Journey: ขั้นตอนการสร้างระเบียบโลกใหม่

เราจะใช้พลังของ NestJS ในการดักจับข้อมูลทุุกหยดที่ไหลเข้า-ออกแอป

🛠 Step-by-step:

  1. Standardize Response: ใช้ Interceptor ห่อข้อมูลทุุกอันด้วย Schema เดียวกัน
  2. Catch Exceptions: ใช้ Exception Filter เพื่อแปลง Error น่ากลัวๆ ให้เป็น JSON ที่อ่านออก
  3. Audit Log: ใช้ Logger ที่มี Context ชัดเจน (รู้ว่า Error มาจากไฟล์ไหน บรรทัดไหน)
HLJS TYPESCRIPT
// ✅ Best Practice: แปลงร่างทุุก Response ให้มีมาตรฐาน
@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    return next.handle().pipe(
      map((data) => ({
        data, // 🛠 ห่อหุ้มข้อมูลจริง
        statusCode: context.switchToHttp().getResponse().statusCode,
        timestamp: new Date().toISOString(),
      })),
    );
  }
}

🪤 4. The Junior Trap: โรค "Try-Catch ทุกที่"

จูเนียร์มักจะกลัวโค้ดพังจนต้องเขียน try-catch หุ้มทุุกฟังก์ชัน:

HLJS TYPESCRIPT
// ❌ Junior Trap: เขียนโค้ดซ้ำซ้อนจนอ่านไม่ออก
async findAll() {
  try {
    return await this.userRepo.find();
  } catch (e) {
    throw new HttpException("พังจ้า", 500); // 🌋 เขียนแบบนี้ 100 ที่ก็พ่ายแพ้ 100 รอบ
  }
}

ระวัง: การ try-catch ทุุกจุดคือการสร้าง Technical Debt มหาศาล ✅ การแก้ไข: ปล่อยให้ Error มันพุ่งขึ้นไป (Bubble up) แล้วให้ Global Exception Filter ตัวที่เดียวจัดการ ท่านี้จะทำให้โค้ด Business Logic ของคุณสะอาดขึ้น 80% ทันที!


⚖️ 5. The Why Matrix: ทำไมต้องแยก Interceptor กับ Filter?

หัวข้อInterceptor (ขาสำเร็จ)Exception Filter (ขาพัง)
หน้าที่หลักตกแต่ง/เปลี่ยนแปลงข้อมูลดักจับและจัดระเบียบ Error
จังหวะการทำงานก่อนและหลังเข้า Methodเมื่อเกิด Exception เท่านั้น
ความยืดหยุ่น⚡⚡⚡ สูง (เปลี่ยนค่าได้เลย)⚡⚡ ชัดเจน (โฟกัสแค่เรื่อง Error)
เหมาะกับFormatting, Logging, CachingAPI Error, Validation, Logging

🎓 6. Senior Mindset Summary

การเป็น Senior คือการมองว่า "ความล้มเหลวคือสิ่งที่คาดเดาได้". การออกแบบ API ที่ดีไม่ใช่การทำให้มันไม่ล่ม แต่คือการทำให้เมื่อมันล่มแล้ว "ระบบยังสื่อสารได้อย่างเป็นมืออาชีพ" และ "ทิ้งร่องรอยให้ตามแก้ได้ง่าย" ครับ!

Share this note

© 2026 My Notes by Seereen