μ΄μ μ URL μ λ²μλ₯Ό λμ΄κ°λ index λ₯Ό μ λ ₯νμ¬ request νλ©΄, JSON ννλ‘ error data κ° response λ κ²μ μ μ μμλ€.
κ·Έλ λ€λ©΄ Server μ Exception Handler λ₯Ό λ§λ€μ΄ λ¨μν status code 500 μ Internal Server Error κ° μλ, λ μ νν κ·Όκ±°μ ν¨κ» νμ μΌκ΄λ νμμ error message λ₯Ό response νλλ‘ λ§λ€λ©΄ μ΄λ¨κΉ?
Spring REST Exception Handling

μμ κ°μ΄, bad request κ° λ€μ΄μμ λ, Exception Handler κ° λ°λ‘ μ²λ¦¬νλλ‘ νμ¬ μ λλ error message λ₯Ό JSON μ ννλ‘ response νκ² λ§λ€μ΄λ³΄μ. Development Process λ λ€μκ³Ό κ°λ€.
- custom error reponse class λ₯Ό μμ±
- custom exception class λ₯Ό μμ±
- λ§μ½ ν΄λΉνλ student κ° μμ κ²½μ° exception μ throw νλλ‘ REST service λ₯Ό update
@ExceptionHandlerannotation μ μ¬μ©νμ¬ exception handler method λ₯Ό μΆκ°
Step 1: Create custom error response class
public class StudentErrorResponse {
private int status;
private String message;
private long timeStamp;
...
}μ¬κΈ°μλ response message μ body μ λ€μ΄κ° λ΄μ©μ define νλ€. POJO μ ννλ‘, μνλ field λ€μ μ ννμ¬ class λ₯Ό ꡬμ±νλ€.
Step 2: Create custom student exception
public class StudentNotFoundException extends RuntimeException {
public StudentNotFoundException(String message) {
super(message);
}
}REST service μμ ν΄λΉνλ νμμ μ°Ύμ§ λͺ»νμ λ exception μ throw νκ² λ 건λ°, μ΄ exception μ define ν΄μ£Όμ΄μΌ νλ€. μ΄μ custom student exception class λ₯Ό μμ±νμ¬ μ¬κΈ°μ exception μ define ν΄μ€λ€.
ν΄λΉ class λ RuntimeException μ μμλ°κ³ , super constructor λ₯Ό μ¬μ©νμ¬ parent class μ constructor λ₯Ό μ¬μ©νμ¬ message λ₯Ό parent class μ field μ μ μ₯νλ€.
Step 3: Update REST service to throw exception
@GetMapping("/student/{studentId}")
Student getStudent(@PathVariable int studentId) {
// check the studentId against list size
if ((studentId >= theStudents.size()) || (studentId < 0)) {
throw new StudentNotFoundException("Student id not found - " + studentId);
}
return theStudents.get(studentId);
}κΈ°μ‘΄μ getStudent method μ studentId μ λ²μλ₯Ό 체ν¬νλ logic μ μΆκ°νμ¬ StudentNotFoundException μ throw νλλ‘ νλ€.
Step 4: Add exception handler method
@ExceptionHandler
public ResponseEntity<StudentErrorResponse> handleException(StudentNotFoundException exception) {
// create a StudentErrorResponse
StudentErrorResponse error = new StudentErrorResponse();
error.setStatus(HttpStatus.NOT_FOUND.value());
error.setMessage(exception.getMessage());
error.setTimeStamp(System.currentTimeMillis());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}@ExceptionHandler annotation μ μ¬μ©νμ¬ exception handler method λ₯Ό define νλ€. ν΄λΉ annotation μ νΉμ exception μ μ²λ¦¬νκΈ° μνμ¬ μ§μ νλλ°, μ¬κΈ°μλ StudentNotFoundException μ΄ λ°μνμμ λ μ΄ method κ° call λλ€. μ¦, parameter μ type μ ν΄λΉνλ exception μ΄ λ°μνμ κ²½μ°μλ§ ν΄λΉ method κ° call λλ κ²μ΄λ€.
exception handler λ ResponseEntity type μ object λ₯Ό return νλλ°, μ΄ object λ₯Ό ν΅νμ¬ HTTP status code, HTTP headers, Response body λ₯Ό μ μ°νκ² μ€μ ν μ μλ€.
μ΄μ μ μμ±ν StudentErrorResponse class μ κ° field λ₯Ό setter λ₯Ό ν΅νμ¬ κ°μ μ€μ ν΄μ£Όκ³ , ResponseEntity object λ₯Ό return νλ€. ResponseEntity μ λ΄λΆ ꡬνμ 보면,
public class ResponseEntity<T> extends HttpEntity<T> {
private final HttpStatusCode status;
public ResponseEntity(@Nullable T body, HttpStatusCode status) {
this(body, (MultiValueMap)null, status);
}
...
}κ³Ό κ°μ΄ λμ΄μλλ°, constructor μ 첫 λ²μ§Έ parameter λ body λ‘, λ λ²μ§Έ parameter λ status λ‘ μ¬μ©λ¨μ μ μ μλ€. λ°λΌμ, body λ StudentErrorResponse object λ‘, status λ HttpStatus.NOT_FOUND λ‘ initailize λ ResponseEntity object κ° return λλ€.
REST Exception Handling - Test
http://localhost:8080/api/student/9999 μΌλ‘ request λ₯Ό 보λ΄κ³ response κ²°κ³Όλ₯Ό νμΈν΄λ³΄λ©΄ μμ κ°λ€. μ°μ exception handler μμ μ€μ ν΄μ€λλ‘, body λΆλΆμλ StudentErrorResponse object κ° JSON formate μΌλ‘ client μ μ λ¬λ κ²μ λ³Ό μ μμΌλ©°, status λ λ¨μν Internal Server Error μλ λͺ
μμ μΌλ‘ μ€μ ν΄μ€ HttpStatus.NOT_FOUND, μ¦ 404 κ° μ λ¬λ κ²μ λ³Ό μ μλ€.
νΉμ studentId μ integer κ° μλ λ¬Έμμ΄μ λ£μ΄ request λ₯Ό 보λ΄λ©΄ μ΄λ»κ² λ κΉ?
μ΄λ²μλ μ§μ λ§λ exception handler λ₯Ό κ±°μΉμ§ μκ³ λ€λ₯Έ error message κ° response λμλ€. κ·ΈλΌ μ΄λ° corner case, νΉμ edge case λ€μ λν΄μλ custom exception handler λ₯Ό κ±°μΉκ² νλ €λ©΄ μ΄λ»κ² μ²λ¦¬ν΄μΌ ν κΉ?
REST Exception Handling - Edge Case
@ExceptionHandler
public ResponseEntity<StudentErrorResponse> handleException(Exception exc) {
StudentErrorResponse error = new StudentErrorResponse();
error.setStatus(HttpStatus.BAD_REQUEST.value());
error.setMessage(exc.getMessage());
error.setTimeStamp(System.currentTimeMillis());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}λ°©λ²μ μΆκ°μ μΈ exception handler λ₯Ό νλ λ μμ±νλ κ²μ΄λ€. μ΄ handler μλ parameter λ‘ Exception class λ₯Ό λ°κ³ μμΌλ―λ‘, νΉμ exception μ΄ μλ generic ν exception μ μ²λ¦¬νλ λ° μ¬μ©λλ€.
error object μλ NOT_FOUND κ° μλ BAD_REQUEST λ₯Ό status λ‘ μ€μ νλ€. μ΄λ κ² λλ©΄ request μ νμμ λ§μΌλ ν΄λΉ νμμ μ°Ύμ μ μλ€λ μ€λ₯μ, request νμμ΄λ data κ° μ ν¨νμ§ μμ κ²½μ°λ₯Ό λλμ΄μ exception handling ν μ μκ² λλ€.
κ°λ¨νκ² test ν΄λ³΄λ©΄ body μ status code λ μλλλλ‘ μ response λ κ²μ λ³Ό μ μλ€.