본문 바로가기

Back-End/SpringBoot

[SpringBoot/WebClient] WebClient ClientResponse로 성공/실패 응답 객체 각각 받기

토스 결제 API 연동 중

성공 시 응답

{
  "mId": "tosspayments",
  "version": "2022-06-08",
  "paymentKey": "T1UwdsBoNhvzO-fUy8BkC",
  "status": "DONE",
  "transactionKey": "-93-dcZeXmDd_pUfnKIwA",
  "lastTransactionKey": "MSmTdHS56DmjArbD2PeDM",
  "orderId": "xwFi1a_v3pidotzeXqkiE",
  "orderName": "토스 티셔츠 외 2건",
  "requestedAt": "2022-06-08T15:40:09+09:00",
  "approvedAt": "2022-06-08T15:40:49+09:00",
  "useEscrow": false,
  "cultureExpense": false,
  "card": {
    "company": "농협",
    "number": "123456******7890",
    "installmentPlanMonths": 0,
    "isInterestFree": false,
    "interestPayer": null,
    "approveNo": "00000000",
    "useCardPoint": false,
    "cardType": "신용",
    "ownerType": "개인",
    "acquireStatus": "READY",
    "receiptUrl": "https://dashboard.tosspayments.com/sales-slip?transactionId=KAgfjGxIqVVXDxOiSW1wUnRWBS1dszn3DKcuhpm7mQlKP0iOdgPCKmwEdYglIHX&ref=PX",
    "amount": 15000
  },
  "virtualAccount": null,
  "transfer": null,
  "mobilePhone": null,
  "giftCertificate": null,
  "cashReceipt": null,
  "discount": null,
  "cancels": null,
  "secret": null,
  "type": "NORMAL",
  "easyPay": null,
  "country": "KR",
  "failure": null,
  "isPartialCancelable": true,
  "receipt": {
    "url": "https://dashboard.tosspayments.com/sales-slip?transactionId=KAgfjGxIqVVXDxOiSW1wUnRWBS1dszn3DKcuhpm7mQlKP0iOdgPCKmwEdYglIHX&ref=PX"
  },
  "currency": "KRW",
  "totalAmount": 15000,
  "balanceAmount": 15000,
  "suppliedAmount": 13636,
  "vat": 1364,
  "taxFreeAmount": 0,
  "method": "카드"
}

 

실패 시 응답

{
  "code": "NOT_FOUND_PAYMENT",
  "message": "존재하지 않는 결제 입니다."
}

이렇게 성공/실패 시 받는 객체가 달라서 bodyToMono를 성공 객체로만 받아서는 실패 시 응답 메세지를 클라이언트쪽에 리턴에 줄 수 없었다.

구글링 해보니 clientResponse로 응답 코드에 따라 객체를 다르게 받는 법을 찾았다.

 

@Service
@Slf4j
@RequiredArgsConstructor
public class TossPaymentApproveService {

    private static final String END_POINT = "/v1/payments/{paymentKey}";
    private final TossApiConfig tossApiConfig;

    public Object approve(String paymentKey, TossPaymentDTO.ApproveRequest request) {
        return WebClient.create(tossApiConfig.getUrl()).post()
            .uri(uriBuilder -> uriBuilder
                .path(END_POINT)
                .build(paymentKey))
            .header(AUTHORIZATION, tossApiConfig.getBasicSecretKey())
            .header(CONTENT_TYPE, "application/json")
            .bodyValue(request)
            .exchangeToMono(clientResponse -> getResponseObject(clientResponse))
            .block();
    }


    private Mono<Object> getResponseObject(ClientResponse clientResponse) {
        if (clientResponse.statusCode().isError()) {
            return clientResponse.bodyToMono(ApproveErrorResponse.class);
        }
        return clientResponse.bodyToMono(ApproveResponse.class);
    }
}

200 응답 시 ApproveResponse 객체로 받고, 200 이 외는 ApproveErrorResponse 객체로 받도록 했다.

 

+ 이후 받은 객체를 판별하여 error response는 예외 처리한다.

    private ApproveResponse validateResponse(Object response) {
        if (response instanceof ApproveResponse) {
            return (ApproveResponse) response;
        }
        if (response instanceof ApproveErrorResponse) {
            throw new CommonException(ResponseCode.API_REQUEST_FAIL,
                ((ApproveErrorResponse) response).getMessage());
        }
        throw new CommonException(ResponseCode.INVALID_RESPONSE);
    }

 

참조

https://stackoverflow.com/questions/49485523/get-api-response-error-message-using-web-client-mono-in-spring-boot

 

Get API response error message using Web Client Mono in Spring Boot

I am using webflux Mono (in Spring boot 5) to consume an external API. I am able to get data well when the API response status code is 200, but when the API returns an error I am not able to retrie...

stackoverflow.com