เลิกครอบ try-catch ใน Controller จัดการ Error ให้เป็นมาตรฐานด้วย ProblemDetail (Spring Boot 3+)
February 04, 2026
·
2 min read
·
1 views
คุณเคยเขียน Controller ที่เต็มไปด้วย try-catch เพื่อดัก Error แล้วปั้น Response กลับไปหา User ไหม?
Code ที่ Dev ส่วนใหญ่เหนื่อยที่จะเขียน:
java
@GetMapping("/users/{id}")
public ResponseEntity<?> getUser(@PathVariable Long id) {
try {
User user = userService.findById(id);
return ResponseEntity.ok(user);
} catch (UserNotFoundException e) {
// ต้องมานั่งปั้น Error Object เองทุกที่
return ResponseEntity.status(404)
.body(new MyErrorDto("USER_NOT_FOUND", e.getMessage()));
} catch (Exception e) {
return ResponseEntity.status(500)
.body(new MyErrorDto("INTERNAL_ERROR", "Something went wrong"));
}
}
ปัญหาคืออะไร? (The Impact)
- Code รก: Controller ควรมีหน้าที่แค่รับ Request และส่งต่อ Service ไม่ใช่ที่รวม Logic การจัดการ Error
- ไม่เสถียร (Inconsistent): บาง endpoint ส่ง error หน้าตาแบบ
{ message: ... }บางอันส่ง{ error_code: ... }Frontend ปวดหัวแน่นอน - เหนื่อย: ต้องเขียน
try-catchซ้ำๆ ทุก Method เป็นร้อยๆ จุด
ทางออก: @ControllerAdvice ผสานร่าง ProblemDetail
ใน Spring Boot 3 มีของเล่นใหม่คือ ProblemDetail ซึ่งเป็นมาตรฐานสากล (RFC 7807) สำหรับการส่ง Error API โดยเฉพาะ เราแค่ประกาศตัวดักจับ (Handler) ไว้ที่เดียว แล้ว Controller ของเราจะเหลือแค่ "Happy Path"
1. Controller จะสะอาดวิ้ง:
java
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// เรียก Service ตรงๆ ไม่ต้องสน try-catch
// ถ้าไม่เจอ User เดี๋ยว Service throw Exception ออกมาเอง
return userService.findById(id);
}
2. สร้าง Global Exception Handler:
java
@RestControllerAdvice // บอก Spring ว่า class นี้คอยดัก Error จากทุก Controller
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class) // ดักเฉพาะ Error นี้
public ProblemDetail handleUserNotFound(UserNotFoundException e) {
// Spring Boot 3 สร้าง Object มาตรฐานให้เลย
ProblemDetail problem = ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND,
e.getMessage()
);
problem.setTitle("User Not Found");
problem.setProperty("customCode", "ERR-001"); // เพิ่ม field พิเศษได้
return problem;
}
}
ผลลัพธ์ JSON ที่ได้ (มาตรฐาน RFC 7807):
json
{
"type": "about:blank",
"title": "User Not Found",
"status": 404,
"detail": "User with id 123 does not exist",
"instance": "/users/123",
"customCode": "ERR-001"
}
ความแตกต่างของผลลัพธ์ที่ได้
- Clean Code 100%: Controller ของคุณจะเหลือบรรทัดเดียว อ่านง่าย สบายตา
- Standardization: ทุก Error ในระบบจะมีโครงสร้าง JSON เหมือนกันหมด (Frontend ยิ้มแก้มปริ เขียนตัวดัก Error ที่เดียวจบ)
- Separation of Concerns: แยก Logic การทำงาน (Service) ออกจาก Logic การจัดการ Error (Advice) อย่างชัดเจน
บทสรุป
เลิกกลัว Exception จนต้องรีบ catch มันไว้ทุกที่ครับ ปล่อยให้มัน throw ออกมา แล้วใช้ @RestControllerAdvice ดักจัดการทีเดียว นี่คือวิธีที่ทำให้ Code Base ขนาดใหญ่ยังคงดูสะอาดและดูแลรักษาง่ายครับ
No responses yet. Be the first to respond.