API 예외 처리는 매우 복잡하다.
시스템마다 응답, 스펙도 다르고 단순히 오류 하면을 보여주는 것이 아니라 예외에 따라서 각각 다른 데이터를 출력해야 할 수도 있다.
BasicErrorController, HandlerExceptionResolver를 직접 구현하는 것으로는 API 예외를 다루는 것은 쉽지 않다.
스프링은 @ExceptionHandler라는 애너테이션을 제공하는데 API 예외처리는 이 기능을 많이 사용한다.
1. IllegalArgumentException 처리
@Slf4j
@RestController
public class ApiExceptionV2Controller {
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalExHandler(IllegalArgumentException e) {
log.error("[exceptionHandler] ex", e);
return new ErrorResult("BAD", e.getMessage());
}
@GetMapping("/api2/members/{id}")
public MemberDto getMember(@PathVariable("id") String id) {
if (id.equals("ex")) {
throw new RuntimeException("잘못된 사용자");
}
if (id.equals("bad")) {
throw new IllegalArgumentException("잘못된 입력 값");
}
if (id.equals("user-ex")) {
throw new IllegalArgumentException("사용자 오류");
}
return new MemberDto(id, "hello " + id);
}
@Data
@AllArgsConstructor
static class MemberDto {
private String memberId;
private String name;
}
}
이 코드를 실행하면 아래와 같은 결과가 나온다. code와 message를 보고 잘 실행된 것 아닌가? 할 수 있겠지만 HTTP 상태 코드를 보면 200 OK 라는 정상 처리 코드가 뜬 것을 확인할 수 있다.
에러가 발생했는데 200이 뜬 이유는 ExceptionResolver가 예외를 처리하고 정상 흐름으로 바꿨기 때문이다.
하지만 우리가 원하는 것은 예외를 정상흐름으로 바꾸는 것이 아니라 400으로 바꾸는 것이기 때문에 @ResponseStatus를 이용해서 원하는 HTTP 상태 코드를 지정할 수 있다.
@ResponseStatus로 상태코드 바꾸기
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalExHandler(IllegalArgumentException e) {
log.error("[exceptionHandler] ex", e);
return new ErrorResult("BAD", e.getMessage());
}
2. ResponseEntity 사용
@ExceptionHandler
public ResponseEntity<ErrorResult> userExHandle(UserException e) {
log.error("[exceptionHandler] ex", e);
ErrorResult errorResult = new ErrorResult("USER-EX", e.getMessage());
return new ResponseEntity<>(errorResult, HttpStatus.BAD_REQUEST);
}
ResponseEntity는 HTTP 메시지 바디에 직접 응답을 보낼 때 응답코드와 더불어 상세한 정보들을 같이 보낼 수 있다.
@ExceptionHandler에서 어떤 Exception 클래스를 잡을지 생략하면 메서드의 파라미터 예외를 사용한다.
여기서는 UserException이 사용된다.
3. Exception 예외
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exHandle(Exception e) {
log.error("[exceptionHandle] ex", e);
return new ErrorResult("EX", "내부 오류");
}
스프링에서 우선순위는 세밀하고 구체적일수록 높다. Exception은 모든 에러의 최상위이기 때문에 1,2번에서 사용한 예외보다는 우선순위가 낮다. 즉, 여기서는 1,2번에서 잡지 못 한 예외들을 처리한다.
출처 : 인프런 - 스프링 MVC 2편 (김영한)
'Spring > Spring' 카테고리의 다른 글
[Spring] 서블릿 예외 처리 - 인터셉터 (0) | 2024.12.05 |
---|---|
[Spring] 서블릿 예외 처리 - 필터 (0) | 2024.12.05 |
[Spring] 서블릿 예외 처리 -1 (0) | 2024.12.04 |
[Spring] 스프링 인터셉터 (0) | 2024.12.03 |
[Spring] 서블릿 필터 (2) | 2024.12.02 |