// 일반적으로는 다른 서버를 호출하지만 본 예제에서는 단순하게 구성하기 위해 자기 자신을 호출하게 진행 funpostUser(name: String, email: String) = "$host/b-service" .httpPost() .header(Headers.CONTENT_TYPE, "application/json") .jsonBody( """ { "name": "$name", "email": "$email" } """.trimIndent() ) .response() }
a-service -> b-service 호출을 한다고 가정했을 경우 b-service에서 HTTP Status가 2xx가 아닌 경우, 특히 4xx가 발생하는 경우로 요청한 여려의 필드 중에 1개 이상의 오류가 있는 경우가 빈번하게 있기 때문에 b-service의 Error 응답을 그대로 전달해 줘야 하는 경우가 있습니다.
그런데 문제가 있습니다. 서비스 로직에서 b-service에서 발생한 Error 응답을 그대로 클라이언트에게 전달하기가 어렵습니다. 이 문제를 Spring Guide - Exception 전략에서 사용한 @ControllerAdvice을 통해서 예외를 핸들링을 통해서 해결해 보겠습니다.
발생한 Error 응답을 그대로 전달 하기
예외 클래스 정의
1 2 3
class ApiException( val errorResponse: ErrorResponse ) : ServiceException(ErrorCode.SERVICE_ERROR, ErrorCode.SERVICE_ERROR.message) // Error Code가 실질적으로 진행하는 것은 없지만 필수 값이라 전달
비즈니스 예외를 관리하는 예외 클래스를 정의하고, Error JSON에 맞는 Error Response 객체를 필수 값으로 받게 합니다.
a-service -> b-service를 호출했고 요청 필드에 문제가 있어 b-service에서 내려준 응답을 그대로 a-service에서 내려주는 것을 디버깅 모드로 확인해 보겠습니다.
서비스 코드에서 400 응답을 받는 것을 확인할 수 있습니다.
ApiException에 대한 에러 핸들링이 GlobalExceptionHandler에서 정상적으로 동작하는 것을 확인할 수 있습니다. 전달받은 Error Response 객체도 정확하게 바인딩 됐습니다.
정리
여러 API를 호출하여 요구사항을 만족시키는 경우가 일반적입니다. 그러한 경우 Error Respone를 최초 호출한 클라이언트에게 전달해야 하는 경우가 있으며 이런 경우 위 같은 형식으로 해당 기능을 만족시킬 수 있습니다. 하지만 서버에 대한 통제권이 없고 Error Response에 대한 통일이 없다면 해당 방법은 어려운 부분이 있습니다. 또 Error Response에 대한 내용을 그대로 전달하는 것도 보안에 좋지 않기 때문에 회사 내부에서만 사용하는 경우가 아닌 유저향 서비스 시에는 조금 더 신중하게 Error 응답을 전달해야 합니다.