Toby의 ReactiveProgramming

Spring 6의 새로운 HTTP Interface와 3가지 REST Clients

webmaster 2023. 6. 6. 22:40
728x90

RestTemplate

@SpringBootApplication
public class RestApplication {

  @Bean
  public ApplicationRunner init(ErApi api) {
    return args -> {
      //https://open.er-api.com/v6/latest
      RestTemplate rt = new RestTemplate();
      /*
      String res = rt.getForObject("https://open.er-api.com/v6/latest", String.class);
      System.out.println(res);
       */
      Map<String, Map<String, Double>> res = rt.getForObject("https://open.er-api.com/v6/latest",
          Map.class);
      System.out.println(res.get("rates").get("KRW")); //header 를 넣거나 post 방식 요청이 힘들다.
    };
  }
  public static void main(String[] args) {
    SpringApplication.run(RestApplication.class, args);
  }

}
  • RestTemplate 같은 경우, getForObject 메서드를 사용하면 API 통신이 가능하다.
    • 1번째 파라미터에는 URI
    • 2번째 파라미터에는 반환받을 Class 타입 -> 보통은 DTO를 만들어서 반환받는다.
    • 3번째 파라미터에는 전달할 UriValue를 작성한다(현재는 없다.)
  • 매우 간단하게 사용 가능하며, Reactive 스타일을 사용하지 않고, get 방식으로 가지고 올 거면 RestTemplate를 사용하여도 된다.

WebClient

@SpringBootApplication
public class RestApplication {

  @Bean
  public ApplicationRunner init(ErApi api) {
    return args -> {
      WebClient client = WebClient.create("https://open.er-api.com");
      Map<String, Map<String, Double>> res2 = client.get().uri("/v6/latest").retrieve()
          .bodyToMono(Map.class).block();
      System.out.println(res2.get("rates").get("KRW"));
    };
  }
  public static void main(String[] args) {
    SpringApplication.run(RestApplication.class, args);
  }

}
  • WebClient 방식을 사용하면, Reactive 한 형식으로 API를 호출할 수 있다(Mono, Flux 타입으로 반환)
  • 비동기 호출이 가능하지만 현재는 동기식으로 block()을 사용하였다.
  • RestTemplate 보다 모던하게 API를 작성할 수 있다.
    • 자동완성 기능을 통해 좀 더 모던하게 API 호출을 할 수 있다
    • Header을 값 세팅이 RestTemplate보다 간편하다.
    • Post, Put 등 다양한 메서드를 보다 간편하게 호출할 수 있다.
  • 내 Application이 Reactive 방식으로 작성을 하였다면..? WebClient를 사용하자

HTTP Interface

RestApplication

@SpringBootApplication
public class RestApplication {

  @Bean
  public ApplicationRunner init(ErApi api) {
    return args -> {
      HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builder(
              WebClientAdapter.forClient(client))
          .build();
      ErApi erApi = httpServiceProxyFactory.createClient(ErApi.class);
      Map<String, Map<String, Double>> res3 = erApi.getLatest();
      System.out.println(res3.get("rates").get("KRW"));

      Map<String, Map<String, Double>> res4 = erApi.getLatest();
      System.out.println(res4.get("rates").get("KRW"));
    };
  }

  public interface ErApi {
    @GetExchange("/v6/latest")
    Map getLatest();
  }

  public static void main(String[] args) {
    SpringApplication.run(RestApplication.class, args);
  }

}

RestConfiguration

@Configuration
public class RestConfiguration {

  @Bean
  public ErApi erApi(){
    WebClient client = WebClient.create("https://open.er-api.com");
    HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builder(
            WebClientAdapter.forClient(client))
        .build();

    return httpServiceProxyFactory.createClient(ErApi.class);
  }
}
  • interface를 정의하고, 어노테이션을 다는 방식으로 작성한다. 
    • 아직 해당 Interface를 구현하여, 빈으로 등록하는 부분은 수동으로 해야 한다 -> 조만간 Spring에서 이를 자동화하지 않을까 예상된다.
  • 인터페이스를 구현한 객체를 Bean으로 등록만 해준다면?? 클라이언트(사용자)는 내부적으로 어떻게 동작하는지 알 필요 없이, bean만 주입받아 사용하면 된다
    • feign을 사용하고 있다면 변경을 고려해 볼 만도 하다.
  • @RequestHeader, @RequestBody 어노테이션을 조합하여 header, body 값을 전달하면 된다
  • 오류 핸들링 같은 경우 WebClient 같은 경우 4xx, 5xx 에러는 WebClientResponseException을 반환하는데, 이를 핸들링 하여 오류를 처리하면 된다.

https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-http-interface

 

REST Clients :: Spring Framework

WebClient is a non-blocking, reactive client to perform HTTP requests. It was introduced in 5.0 and offers an alternative to the RestTemplate, with support for synchronous, asynchronous, and streaming scenarios. WebClient supports the following: Non-blocki

docs.spring.io

 

728x90

'Toby의 ReactiveProgramming' 카테고리의 다른 글

Flux의 특징과 활용방법  (0) 2022.08.30
Mono의 동작방식과 block()  (0) 2022.08.28
WebFlux  (0) 2022.08.28
CompletableFuture  (0) 2022.08.27
AsyncRestTemplate의 콜백 헬과 중복 작업 문제  (0) 2022.08.26