외부 API를 통해 여러 정보를 받아와야 한다.
이때 Rest Template가 아닌 Web client를 사용하여 이를 수행하였다.
이전 프로젝트에서는 rest template을 사용하였지만 deprecated 된다고 하여 web client를 사용하였다.
📍web client는 non-blocking, 즉 동기 방식으로 수행되지만 현재 프로젝트에서는 이를 비동기로 수행하였다. Web client의 사용 이유는 오직 rest template의 deprecated issue이다.
목차
1. web client 특징
2. 사용한 코드와 메소드 설명
3. 발생한 문제와 해결방안
📌 여기서 Spring WebFlux란?
Spring 5에서 새롭게 추가된 모듈로 클라이언트, 서버에서 reactive 스타일의 어플리케이션 개발을 도와주는 모듈이다.
목적: 외부 API 사용하여 여러 장소 정보를 받아오기 위함
private final WebClient webClient;
private final String BASE_URL="https://dapi.kakao.com";
public ShopServiceImpl(WebClient.Builder webclientBuilder, @Value("${external.api.key}")String key) {
DefaultUriBuilderFactory factory=new DefaultUriBuilderFactory(BASE_URL);
factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.TEMPLATE_AND_VALUES);
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofMillis(5000))
.doOnConnected(conn ->
conn.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)));
this.webClient = webclientBuilder.uriBuilderFactory(factory).baseUrl(BASE_URL)
.defaultHeader("Authorization",key)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
저는 따로 @Configuration @Bean을 통하여 web client를 bean으로 생성하지 않고 생성자 주입 방식으로 생성하였습니다.
🦷 WebClient.Builder를 DI하는 방식으로 수행합니다.
이렇게 수행한 이유는 제일 직관적이고 편리한 것 같아서 + 공식문서에서 이렇게 하길래 ...
-> Webclient.create()를 수행하면 세부 설정이 불가함.
Webclient로 REST 서비스 호출하기
해당 공식문서를 따라가면 좋다.
Response res= webClient.get().uri(uriBuilder ->
uriBuilder.path("해당하는 uri")
.queryParam("query",query)
.build()
).retrieve().bodyToMono(Response.class).block();
Http get 방식을 사용하여 Response를 받았다.
retrive()
response body를 받아 디코딩하는 메소드
bodyToMono(Response.class)
header 등 여러 정보 필요 없이 body만을 받아 특정 객체로 변환하는 method
method 인자에 반환받을 객체.class를 넣어줘야 한다.
block()
non-blocking이 아닌 block 형식으로 동기적으로 받기 위한 메소드
📌 block 메소드를 사용하였기 때문에 이는 비동기가 아닌 동기로 수행합니다.
2번에 작성한 코드가 이미 이를 고친 것이긴 하지만,
원래는 api key를 @value로 주입할 때 생성자가 아닌 멤버 변수로 주입하였다.
하지만 web client 생성 시에 defaultheader에 authorization을 넣어줘야 했고 @value 어노테이션은 이보다 뒤에 수행되기 때문에 key가 null값으로 들어가게 되었다.
그래서 생성자에서 @value annotation 인자로 받아오게 되었다.
spring이나 spring boot를 이론을 파면서 공부한 적이 많이 없어서 그런지 어려움이 많은 것 같다. Web Flux나 spring framework 위에서의 동기/비동기에 대한 개념이 없는 걸 알게 되었다.
단지 rest template이 deprecated 된다는 이유로 web client를 사용하기는 하였지만 스트리밍 같은 서비스에 사용하면 정말 효과적일 것 같다.
📂 참고한 포스트