Post
KO

feign client, feign configuration

목적

연동된 구간별 API http 응답 코드 별로 예외 메시지 처리를 하기 위함.

ex) 주문 접수 할 때, 연동하는 API가 5가지 일 때, 5가지 마다 각각 다른 예외 처리르 하기 위함 (화면에 메시지 안내 포함)

주말에 한번 Feign Client로 예외 처리 하는 방식을 고민해보았는데요,

(오픈 Feign 뉴비라서 제가 잘 몰라요)

http status 코드 파싱해서 각 구간별 예외 메시지를 처리할까 고민중입니다.

예상 되는 조합 FallbackFactory + ControllerAdvice 조합

혹시 이 방법 보다 더 나은 방법이 있으시면 공유 부탁드립니다.

예제코드

public class CouponErrorDecoder implements ErrorDecoder { private final ObjectMapper om = new ObjectMapper(); /** * 발생된 예외를 catch 해서 custom하게 예외를 처리합니다. * * @param methodKey 호출 메서드 * @param response 응답 데이터 * @return custom Exception */ @SneakyThrows @Override public Exception decode( final String methodKey, final Response response) { final Request request = response.request(); log.info("{} 요청이 성공하지 못했습니다. status : {}, body : {}", methodKey, response.status(), response.body()); FileBeatLogger.info(new HashMap<>() { { put("action", "coupon-request-fail"); put("url", request.url()); put("http status code", response.status()); put("error message", response.body() .toString()); } }); if (Request.HttpMethod.GET == request.httpMethod() && request.url() .contains("restore")) { cancelError(response); } final var error = om.readValue(response.body() .toString(), CouponErrorMessage.class); log.info("{}", error); switch (response.status()) { case 400: return new CouponUseException(5250, error.getMessage()); case 422: case 404: return new CouponUseException(5251, error.getMessage()); default: return new CouponUseException(5252, "쿠폰 API 호출 중 오류가 발생되었습니다."); } } /** * 오류 메시지 파싱 Class. */ @ToString @Data static class CouponErrorMessage { private String message; private boolean success; } /** * 쿠폰 사용취소 exception을 핸들링합니다. */ private Exception cancelError(@NonNull final Response response) { final Request request = response.request(); final int status = response.status(); if (status == 404) { final String message = String.format(":alert: :alert: :alert: 사용되지 않은 쿠폰은 복원할 수 없습니다. url: [%s]", request.url()); log.error(message); SlackNotifier.notify(message); return new CouponCancelException(5253, "사용되지 않은 쿠폰은 취소 할 수 없습니다."); } final String message = String.format(":alert: :alert: :alert: 쿠폰취소 요청 feign 요청이 실패하였습니다. url: [%s]", request.url()); log.error(message); SlackNotifier.notify(message); return FeignException.errorStatus(request.httpMethod() .name(), response); } }
/** * 쿠폰 Feign Configuration. */ public class CouponFeignConfiguration { /** * 쿠폰 ErrorDecoder Bean을 등록합니다. * * @return ErrorDecoder */ @Bean public ErrorDecoder decoder() { return new CouponErrorDecoder(); } /** * 재시도 횟수 설정. * * 최소 기간 0.1초, 최대 0.5초, 재시도 횟수 3회 * */ @Bean Retryer retryer() { return new Retryer.Default(100, 500, 3); } }
/** * 쿠폰 feign Client. */ @FeignClient(name = "coupon-api-service", fallback = CouponFeignClientFallback.class, qualifier = "CouponFeignClient", configuration = CouponFeignConfiguration.class) public interface CouponFeignClient { /** * 쿠폰 사용 처리 요청입니다. * * @param memberNo 회원번호 * @param couponCode 쿠폰코드 * @param orderNo 주문번호 * @return 쿠폰 사용 처리 응답 */ @GetMapping(path = "/v2/order/coupon/{memberNo}/use/{couponCode}/to/{orderNo}") ApiResponseModel use( @PathVariable("memberNo") Long memberNo, @PathVariable("couponCode") Long couponCode, @PathVariable("orderNo") Long orderNo); /** * 쿠폰 사용을 취소 합니다. * * @param memberNo 회원번호 * @param couponCode 쿠폰번호 * @return 쿠폰 사용 취소 응답 */ @GetMapping("/v1/crm/{memberNo}/restore/{couponCode}") ApiResponseModel cancel( @PathVariable("memberNo") Long memberNo, @PathVariable("couponCode") Long couponCode); }

This article is licensed under CC BY 4.0 by the author.