만족은 하되 안주하지는 말자

기록해야 기억한다

프로그래밍/backend&devOps

[Spring] WebClient 를 이용하여 외부 API 데이터를 받아보자

D36choi 2020. 4. 15. 18:00
728x90

- springboot 2

- webFlux

- thymeleaf

 

WebClient? 

https://www.baeldung.com/spring-5-webclient

 

Spring 5 WebClient | Baeldung

Discover Spring 5's WebClient - a new reactive RestTemplate alternative.

www.baeldung.com

Spring 에서 제공하는 REST 클라이언트 중 하나.

RestTemplate 를 많이 활용하였으나 공식적으로 deprecated 되기 때문에 WebClient 를 사용하기로 하였다.

가장 큰 특징은 Asynchronous I/O 방식. 따라서 블로킹되지 않아 기존의 RestTemplate 보다 성능이 좋다.

 

실습해보자

1. 관련 의존성 추가

WebFlux 를 추가해야한다. (mvnrepository 참조)

 

2. WebCllient 사용을 위한 Service 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
 
@Service
public class TestApiService {
    private final WebClient webClient;
 
    public TestApiService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("https://jsonplaceholder.typicode.com").build();
    }
 
    public String getFirstTodosTest() {
        String response =
                this.webClient.get().uri("/todos/1")
                .retrieve().bodyToMono(String.class)
                .block();
        return response;
    }
}
 
cs

이번 연습의 경우, 익히 알려진 JSON 데이터 샘플 사이트인 jsonplaceholder 의 URL 주소를 이용하기로 하였다.

이중에서도 todos 데이터의 1번째를 가져와 간단히 문자열로 보도록 하겠다.

.block(); 이 중요한데, 이게 있어야 String.class 로 변환된 block 을 리턴하게 된다.

그렇지 않은 경우 Mono<String> 을 webClient 는 반환한다.

 

 

3. Controller 만들기

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
import com.naturebox.app.testServices.TestApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
 
@Slf4j
@Controller
public class TestApiController {
 
    final TestApiService testApiService;
 
    @Autowired
    public TestApiController(TestApiService testApiService) {
        this.testApiService = testApiService;
    }
 
    @GetMapping("/Test")
    public String TestWebClient(){
        Model model = null;
        String response = testApiService.getFirstTodosTest();
       model.addAttribute("response",response);
       log.info(response);
        return "test";
    }
}
 
cs

lombok 라이브러리를 활용해 log로도 보고, 내가 익숙한 MVC 패턴을 이용해 thymeleaf 를 사용한 html 페이지에 

해당 데이터를 표시해보도록 하겠다.

현재 Mono & Flux 에 대한 이해가 부족하기에 위와같은 방식으로 테스트하였다...

return "test"; 를 하는 경우 resources/templates 에 위치한 "test.html" 파일을 불러오게 된다.

 

 

4. thymeleaf 이용하여 index.html 만들기

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>for test</h1>
    <p th:text="${#strings.toString(response)}"></p>
</body>
</html>
cs

나도 thymeleaf 는 써본적이없어서 문법을 조금 알아야했다.

변수를 string 으로써 출력하는 기본 포맷은 ${#객체} 라고 생각했는데

그렇게 한다면 response 객체가 반환되지 response 객체의 내용이 표시가 되지 않았다.

string 관련 유틸인 strings를 이용해서 response 객체를 toString 하면 가능할까하는 생각에 했는데

이경우에는 잘 작동했다. response String 객체에 참조할때 잘못되었을 가능성이 높다.. 공부가 더 필요할듯..

Mono Flux 와 Block 개념을 더 알아야할듯하다.

 

결과

결과적으로는... todos의 첫번째 데이터를 출력하는데 성공했다.

근데 속도가 좀 느리다. 이게 와이파이 문제인지...

jsonplaceholder 사이트의 접속이 좀 느리던데 그것때문일수도 있다.

 

만약 대용량의 api 데이터를 로드해야한다면 유저가 사이트를 이용하는데 있어 큰 장애물이 될 수 있으니 개발자가 그걸 신경써야겠다는 생각이 들었다!