RestClient를 이용한 Toss 결제 API의 통신과정에서 발생할 수 있는 HttpClientErrorException
을 커스텀 예외로 전환하고 싶었다.
보편적인 방식은 아래와 같았다.
@Override
public PaymentConfirmResponse confirm(
final String orderId,
final Long amount,
final String paymentKey
) {
PaymentConfirmRequest confirmRequest = new PaymentConfirmRequest(orderId, amount, paymentKey);
try {
return restClient
.post()
.uri("/confirm")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(confirmRequest)
.retrieve()
.body(PaymentConfirmResponse.class);
} catch (HttpClientErrorException e) {
log.error(e.getMessage(), e);
throw new PaymentConfirmFailException(e.getMessage(), (HttpStatus) e.getStatusCode());
}
}
바로 해당 메서드를 try-catch로 감싸는 것이다.
하지만 restClient를 살펴보니 onStatus()
라는 에러 발생시 이를 처리할 수 있는 메서드가 존재하였다.
해당 메서드를 사용할 경우에는 아래처럼 코드가 바뀌었다.
@Override
public PaymentConfirmResponse confirm(
final String orderId,
final Long amount,
final String paymentKey
) {
PaymentConfirmRequest confirmRequest = new PaymentConfirmRequest(orderId, amount, paymentKey);
return restClient.post()
.uri("/confirm")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(confirmRequest)
.retrieve()
.onStatus(HttpStatusCode::isError, (request, response) -> {
TossErrorResponse errorResponse =
objectMapper.readValue(response.getBody(), TossErrorResponse.class);
throw new PaymentConfirmFailException(errorResponse.message(), (HttpStatus) response.getStatusCode());
})
.body(PaymentConfirmResponse.class);
}
하지만 이 경우, 의문이 발생했다.
예외를 전환하기 위해서는 전환하기 전의 예외의 Stack Trace를 로그에 남겨두는 것이 일반적이었다.
하지만 메서드를 활용할 경우 에러를 잡아서 처리하는 것이 아닌 상태 코드를 통해 판별하므로 Stack Trace를 로그에 남겨둘 수 없었다.
차이를 보기 위해 일부러 통신과정에서 에러 코드를 헤더에 추가하여 예외를 발생시킨 후 두 StackTrace를 비교하였다.
위에가 try-catch처리, 아래가 onStatus()
로 처리 후 GlobalExceptionHandler
가 예외를 처리한 부분이었다.
두 StackTrace의 차이는 빨간 네모 부분 밖에 없었다.
여기서 두가지 의문이 발생했다.
1. HttpClientErrorException
StackTrace를 남길 수 없다면 onStatus()
메서드는 설계가 잘못 된것이 아닐까?
2. 빨간 부분이 그렇게 중요한가...? StackTrace를 제외한 에러코드와 예외 메세지를 PaymentConfirmFailException
라는 커스텀 예외가 알고 있고, 예외가 발생한 지점에서부터 StackTrace를 갖고 있다면 HttpClientErrorException
를 처리해주지 않아도 되는 것이 아닐까?
혼자 여러 개발 글들을 살펴보았지만 답이 나지 않아 리뷰어에게 여쭤보았다.
리뷰어가 주신 답변을 통해 정리해보니 다음과 같은 결론이 나왔다.
HttpClientErrorException
의 Stack Trace가 필요한 이유는 무엇일까
HttpClientErrorException
의 Stack Trace가 필요한 이유가 뭘까?
1. RestClient 라이브러리 자체의 오동작을 감지하기 위함이다. try-catch로 처리하라
2. 커스텀 예외로 에러 추적이 문제 없다? 그러면 필수는 아니다.
결론을 내리고 생각해보니 마치 테스트 짤 때 고려해야하는 것과 유사하다 느꼈다.
무엇을 StackTrace로 담으려 했는가?
어떤 범위를 StackTrace로 남기고 싶은가?
개인적으로 고민이 될 때 함께 고려할 지표가 생긴 거 같아 기분이 좋다.