사이드 프로젝트를 진행하던 중 팀원의 도움 메시지가 왔습니다.
PR 이후 Github_Action에서 테스트 실패되어 merge를 하지 못하는 상태였습니다. 먼저 실패한 테스트를 확인해봤습니다.
살펴보니 ControllerUnitTest
에서 로그인 실패 시 ErrorResponse를 반환하는데 포맷 문제가 발생한 것이었어요.
근데 생각해보니 이분은 전혀 다른 도메인을 개발중이었는데 문제가 발생했던거죠.
새로 추가한 ControllerAdvice
가 문제였습니다. 서로 같은 예외를 처리하는 메서드였는데, 해당 테스트의 exceptionHandling이 다른 도메인의 handler이 수행하면서 발생한 문제였죠.
예를 들자면 이런 상황인거죠.
이런 오류를 발견하자 마자 다른 ExceptionAdvice 역시 살펴보기 시작했습니다.
공통적으로 보이는 문제가 몇몇개 있더군요!
가장 대표적인 예시로 BindException
이 있습니다. 모든 ControllerAdvice
에서 처리하다보니 중복되는 현상이 발견되고 있습니다. 이는 결국 저희가 겪었던 문제를 발생시키게 되겠죠...
IllegalArgumentException
에 대해서도 예외처리를 한 advice가 몇몇개 있었습니다. 사실 IllegalArgumentException은 정말 많은 라이브러리에서도 심심치않게 사용되는 로직입니다.
만약 다른 라이브러리의 오류로 해당 예외가 발생했을때 사용자의 실수인 것 처럼 예외처리를 해버린다면, 이는 사용자에게 큰 혼동을 안겨주게 됩니다.
Q) Exception Message를 넘겨주는 식으로 분기처라 하면 되는 것 아닌가?
사용자에게는 내부 라이브러리의 오류로 발생하는 문제를 굳이 메시지로 자세히 알려주지 않아도 된다고 생각합니다. 사용자가 굳이 알아야 하는 정보가 아니기 때문입니다.
여러단계를 거쳐서 해결할 에정입니다.
ApplicationException
을 생성할 예정입니다. 이를 구현하면 다음과 같이 됩니다.
@Getter
public class ApplicationException extends RuntimeException {
private HttpStatus httpStatus;
protected ApplicationException(HttpStatus httpStatus, String message) {
super(message);
this.httpStatus = httpStatus;
}
}
public class NotPostWriterException extends ApplicationException {
private static final HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
public NotPostWriterException() {
super(httpStatus, "해당 게시글에 대한 권한이 없습니다.");
}
}
@Slf4j
@RestControllerAdvice
public class GlobalExceptionRestAdvice {
@ExceptionHandler
public ResponseEntity<ResponseDTO<Object>> applicationException(ApplicationException e) {
log.error("ApplicationExcepotion: " + e.getMessage());
return ResponseEntity
.status(e.getHttpStatus())
.body(ResponseDTO.res(e.getHttpStatus(), e.getMessage()));
}
@ExceptionHandler
public ResponseEntity<ResponseDTO<Object>> serverException(RuntimeException e) {
log.error("Server Exception: " + e.getMessage());
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(ResponseDTO.res(HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러!"));
}
...
}
@RestControllerAdvice(basePackages = "com.fasttime.domain.member")
public class MemberControllerAdvice {
@ExceptionHandler
public ResponseEntity<ResponseDTO<Object>> BadCredentialsException(BadCredentialsException e) {
...
}
...
}
다행히 모든 테스트가 정상적으로 통과했습니다! 이제 다른 팀원들은 도메인에 특화된 예외 처리만 진행하면 될 것 같네요!