쌓고 쌓다

API 오류 처리하는법 @ExceptionHandler 본문

프로그래밍/spring

API 오류 처리하는법 @ExceptionHandler

승민아 2023. 12. 4. 20:09

스프링은 API 예외 처리를 위해 @ExceptionHandler 어노테이션을 제공한다.

ExceptionHandlerExceptionResolver는 @ExceptionHandler를 처리한다.

 

먼저, API 요청시 응답으로 보낼 객체를 정의해보자.

 

ErrorResult

@Data
@AllArgsConstructor
public class ErrorResult {
    private String code;
    private String message;
}

 

 

그리고 컨트롤러에서 요청에 대한 응답으로 예외를 던져서 에러를 발생시켜 ErrorResult를 응답으로 보내보자.

@RestController
public class ApiExceptionV2Controller {

    @GetMapping("/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id) {
        if (id.equals("ex")) {
            throw new RuntimeException("잘못된 사용자");
        }
        if (id.equals("bad")) {
            throw new IllegalArgumentException("잘못된 입력 값");
        }
        return new MemberDto(id);
    }
    
}

 

{id}가 "ex", "bad"면 예외를 던진다.

그 외에는 정상적인 JSON 응답을 보낸다.

 

이때 예외가 발생했을때 JSON 응답으로 ErrorResult를 주고싶다면?

 

예외를 처리하길 원하는 컨트롤러에 @ExceptionHandler를 붙여 다음과 같이 작성한다.

@Slf4j
@RestController
public class ApiExceptionV2Controller {

    @ExceptionHandler(IllegalArgumentException.class)
    public ErrorResult illegalExHandler(IllegalArgumentException e) {
        log.error("[exceptionHandler] ", e);
        return new ErrorResult("BAD", e.getMessage());
    }
    
}

 

illegalArgumentException 예외를 던지는 경로로 요청을 보내고 결과를 보자.

응답

ErrorResult로 응답을 줄 수 있다.

 

@ExceptionHandler에서 지정한 예외뿐만 아니라 그 예외의 자식 클래스까지 모두 해당 어노테이션으로 잡을 수 있다.

 

그럼 자식 클래스가 겹치면 어떻게 될까?

 

모든 예외의 부모인 Exception 클래스를 등록해보자.

@ExceptionHandler
public ErrorResult exHandler(Exception e) {
    log.error("[exceptionHandler] ", e);
    return new ErrorResult("EX", "내부 오류");
}

 

그리고 다시 illegalArgumentException을 터트려보자. (illegalArgumentException의 부모에 Exception이 존재한다.)

 

 

@ExceptionHandler(IllegalArgumentException.class)

그래도 동일하게 위의 ExceptionHandler에서 처리가된다.

 

즉, 우선순위는 더 자세한게 우선권을 갖는다.

@ExceptionHandler Exception는 광범위하기에

더욱 상세한 @ExceptionHandler illegalArgumentException이 우선권을 갖고 처리하는 것이다.

 

 

눈여겨 보야할 부분이 또 있다. 상태코드이다.

예외가 발생했지만 200 상태 코드가 나와 정상적인 처리라고 뜬다.

 

 

@ResponseStatus를 사용하여 상태코드를 변경할 수 있다.

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exHandler(Exception e) {
    return new ErrorResult("EX", "내부 오류");
}

상태코드 변경

 

 

다음과 같이 여러 예외를 한번에 처리할 수도 있다.

@ExceptionHandler({AException.class, BException.class})
public String ex(Exception e) {
    ...
}

 

 

*모든 컨트롤러에서 예외를 잡아 처리해주는 것이 아닌. 해당 컨트롤러에서만 잡아주는것임을 주의하자.

주문 컨트롤러와 상품 컨트롤러와 같이 컨트롤러마다 예외 응답을 달리 줄 수 있다는 장점이있다.

 

비로그인이나, 비어있는 데이터이나 등등에 맞춰 에러를 던지는법도 궁금해진다.!

Comments