[WebClient] Spring์—์„œ API ํ˜ธ์ถœํ•˜๊ธฐ

2022. 4. 7. 01:06
๋ฐ˜์‘ํ˜•

๐Ÿ”น ๋ฐฐ๊ฒฝ

์™ธ๋ถ€ API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ/์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์—ฐ์Šตํ•ฉ๋‹ˆ๋‹ค.

Spring์—์„œ HTTP ์š”์ฒญ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” RestTemplate, WebClient๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. RestTemplate์€ Spring 3.0๋ถ€ํ„ฐ ์ง€์›ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์œผ๋ฉฐ, ๋™๊ธฐ์‹ ์š”์ฒญ๋งŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•œ ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ๊ทผ Spring 5.0๋ถ€ํ„ฐ WebClient๋ฅผ ํ‘œ์ค€์œผ๋กœ ์‚ผ์•„ ์Šคํ”„๋ง์—์„œ ๊ถŒ์œ ํ•˜๊ณ  ์žˆ์–ด ์ด๋ฅผ ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

๐Ÿ”น WebClinet๋ž€?

๊ณต์‹๋ฌธ์„œ: https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client
์ฐธ๊ณ ๋ฌธ์„œ: https://www.baeldung.com/spring-5-webclient

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ, WebClient๋Š” ์›น ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์š” ์ง„์ž…์ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.

Spring Web Reactive ๋ชจ๋“ˆ์˜ ์ผ๋ถ€๋กœ ์ œ์ž‘๋˜์—ˆ์œผ๋ฉฐ, ๊ธฐ์กด์˜ Rest Template๋ฅผ ๋Œ€์ฒดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹์œผ๋กœ HTTP/1.1 ํ”„๋กœํ† ์ฝœ์—์„œ ์ž‘๋™ํ•˜๋Š” ๋ฐ˜์‘ํ˜• Non-Blocking ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค.

 

์ด ์†”๋ฃจ์…˜์€ Non-Blocking ํด๋ผ์ด์–ธํŠธ์ด๋ฉฐ Spring-webflux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์†ํ•˜์ง€๋งŒ ๋™๊ธฐ์‹ ์ž‘์—…๊ณผ ๋น„๋™๊ธฐ์‹ ์ž‘์—…์„ ๋ชจ๋‘ ์ง€์›ํ•˜๋ฏ€๋กœ Servlet Stack์—์„œ ์‹คํ–‰๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—๋„ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

 

* Non-Blocking?

Blocking๊ณผ Non-Blocking์€ ์ฃผ๋กœ IO์˜ ์ฝ๊ธฐ, ์“ฐ๊ธฐ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Blocking์€ ์š”์ฒญํ•œ ์ž‘์—…์ด ๋งˆ์น  ๋•Œ๊นŒ์ง€ ๊ณ„์† ๋Œ€๊ธฐํ•˜๋‹ค return ํ•œ๋‹ค๋ฉด, Non-Blocking์€ ์ฆ‰์‹œ ๊ฒฐ๊ณผ๋ฅผ returnํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Non-Blocking์—์„œ ํ•˜๋‚˜์˜ Thread๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ IO๋ฅผ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Non-Blocking์€ ์‹œ์Šคํ…œ์„ ํ˜ธ์ถœํ•œ ์งํ›„์— ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ œ์–ด๊ฐ€ ๋‹ค์‹œ ๋Œ์•„์™€์„œ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์˜ ์ข…๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค์Œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœํ•œ ์‹œ์Šคํ…œ์˜ ๋™์ž‘์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋™์‹œ์— ๋‹ค๋ฅธ ์ž‘์—…์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ž‘์—…์˜ ์†๋„๊ฐ€ ๋นจ๋ผ์ง„๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ”น ๊ฐœ๋ฐœ

Spring Test์—์„œ jsonplaceholder API๋ฅผ ํ˜ธ์ถœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
jsonplaceholder๋Š” ์•„๋ฌด๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋ฉฐ, ์•„๋ž˜ ์˜ˆ์ œ๋Š” https://jsonplaceholder.typicode.com/๋ฅผ ์ด์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

Gradle

implementation 'org.springframework.boot:spring-boot-starter-webflux'

Maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

import org.junit.jupiter.api.Test;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

public class WebClientTest {
    @Test
    void doTest() {
        WebClient client = WebClient.create();
        String url = "https://jsonplaceholder.typicode.com/todos/1";
        Mono<String> stringMono = client.get()
                .uri(url)
                .retrieve()
                .bodyToMono(String.class);
        System.out.println(stringMono.flux().toStream().findFirst());
        System.out.println("์ข…๋ฃŒ");
    }
}

 

๐Ÿ”น ๊ฒฐ๊ณผ

Optional[{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}]
"์ข…๋ฃŒ"

API ์š”์ฒญ ์‘๋‹ต์ด ์ •์ƒ์ ์œผ๋กœ ์˜จ ๊ฒƒ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” WebClient์— Header, Cookie ๋“ฑ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜์—ฌ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, filter๋ฅผ ์ด์šฉํ•œ ์„ธ๋ฐ€ํ•œ ์„ค์ •์„ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๊ธฐ๋Šฅ์„ ๋”ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•

BELATED ARTICLES

more