티스토리 뷰

Spring

[Spring] Spring Boot3.2에 새롭게 추가될 RestClient

망나니개발자 2023. 7. 25. 10:00
반응형

이번에는 Spring Boot3.2에 새롭게 추가될 RestClient에 대해 알아보도록 하겠습니다.

 

 

 

 

1. Spring Boot3.2에 새롭게 추가될 RestClient


[ RestClient가 필요한 이유 ]

Spring에서는 RestTemplate, WebClient와 같은 Http Client를 지원하고 있다. 하지만 이들은 각각 문제점을 가지고 있었다. 대표적으로 RestTemplate은 사용이 직관적이지 못하며, WebClient와 HttpInterface는 web-flux 의존성을 필요로 했다.

2009년에 Spring 3.0에 RestTemplate이 처음 도입된 이후, Template과 같은 클래스를 통해 모든 HTTP의 기능을 노출하는 것이 부담을 줄 수 있다는 것을 발견했다. 그래서 Spring5에 fluent한 API를 지원하는 리액티브 기반의 WebClient를 추가하였다. 하지만 webflux를 필요로 한다는 점이 아쉬웠는데, 이에 대한 대안으로 만들어진 것이 RestClient이며, 서블릿 버전의 WebClient라고 생각하면 된다.

스프링은 Spring 6.1, SpringBoot 3.2부터 새로운 동기식 HTTP 호출 도구인 RestClient를 도입하였다. 이름에서 엿볼 수 있듯이, RestClient는 RestTemplate과 동일한 기반 기술을 바탕으로 fluent한 API를 제공하기 위해 탄생하였다.

RestClient를 사용하면 WebClient와 유사한 방식으로 사용 가능하며, 기존의 message converters, request factories, interceptors 및 RestTemplate의 기타 구성 요소들을 사용할 수 있다.

 

 

 

 

2. RestClient 사용법


[ RestClient 객체 생성하기 ]

create()라는 static 메소드를 사용하면 RestClient 객체를 생성할 수 있다. create의 파라미터로 RestTemplate을 넘겨준다면, 기존에 작성된 RestTemplate의 설정을 기반으로 만들 수도 있다. 또한 builder도 사용할 수 있는데, builder를 사용하면 default url, path variables, headers, interceptors, initializers 등을 설정할 수 있다.

RestClient restClient1 = RestClient.create();
RestClient restClient2 = RestClient.create(restTemplate);
RestClient restClient3 = RestClient.builder()
                .baseUrl("<https://www.naver.com>")
                .build();

 

 

 

[ RestClient를 통한 GET/POST 요청 ]

RestClient를 이용한 GET 요청은 다음과 같이 사용할 수 있다.

RestClient restClient = RestClient.create();

String result = restClient.get()
  .uri("<https://example.com>")
  .retrieve()
  .body(String.class);

 

 

만약 요청 상태 코드나 헤더 등이 필요하다면, ResponseEntity로 반환받을 수도 있다.

ResponseEntity result = restClient.get()
  .uri("<https://example.com>")
  .retrieve()
  .toEntity(String.class);

System.out.println("Response status: " + result.getStatusCode());
System.out.println("Response headers: " + result.getHeaders());
System.out.println("Contents: " + result.getBody());

 

 

RestClient 역시 Json 변환을 지원하며, 마찬가지로 내부에서는 message converters를 사용한다. 따라서 클래스로 변환하여 값을 반환받을 수도 있다.

Pet pet = restClient.get()
  .uri("<https://petclinic.example.com/pets/{id}>", id)
  .accept(APPLICATION_JSON)
  .retrieve()
  .body(Pet.class);

 

 

POST 요청은 다음과 같이 작성할 수 있다.

Pet pet = ...
ResponseEntity response = restClient.post()
  .uri("<https://petclinic.example.com/pets/new>")
  .contentType(APPLICATION_JSON)
  .body(pet)
  .retrieve()
  .toBodilessEntity();

 

 

 

 

[ RestClient의 에러 핸들링 ]

기본적으로 RestClient는 4xx 또는 5xx 상태 코드를 수신하면 RestClientException의 하위 클래스를 throw한다. 해당 동작은 Status Handler를 사용하면 재정의할 수도 있다.

String result = restClient.get()
  .uri("<https://example.com/this-url-does-not-exist>")
  .retrieve()
  .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> {
      throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders())
  })
  .body(String.class);

 

 

 

 

[ RestClient의 exchange ]

exchange 메소드를 사용하면 더욱 advanced 된 시나리오를 다룰 수 있다. exchange 메소드를 통해 내부의 request와 response에 접근할 수 있기 때문이다. 참고로 exchange 메소드를 사용한다면, 이전에 설명했던 Status Handler는 적용되지 않는다. 왜냐하면 exchange를 통해 이미 전체 응답에 대한 접근을 제공하므로 필요한 모든 오류 처리를 수행할 수 있기 때문이다.

Pet result = restClient.get()
  .uri("<https://petclinic.example.com/pets/{id}>", id)
  .accept(APPLICATION_JSON)
  .exchange((request, response) -> {
    if (response.getStatusCode().is4xxClientError()) {
      throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders());
    }
    else {
      Pet pet = convertResponse(response);
      return pet;
    }
  });

 

 

 

Spring6에서 새롭게 제공되었던 기능으로, 인터페이스 기반으로 구현하는 HttpInterface가 있었다. 인터페이스와 어노테이션만으로  아주 편리하게 Client 부분을 구현할 수 있었지만, webflux에 존재하는 WebClient를 사용해야 하는 부분이 아쉬웠다.

하지만 RestClient 역시도 HttpInterface를 지원한다고 하니, 이제 서블릿 기반의 프로젝트(spring-boot-starter-web) 에서는 굳이 webflux 의존성을 사용할 필요가 없을 것 같다.

 

 

 

 

참고 자료

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함