본문 바로가기
코딩일기/날씨앱 만들기 프로젝트

[Spring Boot] WebClient 이용한 API 호출

by 욱파이어니어 2021. 10. 24.
728x90
반응형

일단은 WebClient가 무엇인지부터 살펴보자.

 

 

 

WebClient란?

 

웹으로 API를 호출하기 위해 사용되는 Http Client 모듈 중 하나이다.

WebClient는 non-blocking 방식으로 응답을 기다리지 않고 응답이 왔을때 처리를 해주는 방식이다.

 

이부분에서 RestTemplate과 차이가 난다.

RestTemplate 은 웹으로 API를 호출할때 주로 사용하는 방법이였는데 RestTemplate은 동기 방식으로

API 요청을 하게 되면 응답을 기다리는 방식이다.

 

따라서 사용자가 많아지면 많아 질수록 RestTemplate의 성능은 점차 떨어지게 된다.

 

그래서 그런지 Spring 에서도 웹에서 API를 호출할때 WebClient의 사용을 권장한다.

 

 

WebClient를 사용을 하려면 아래와 같은 순서를 거치게 된다.

 

1. dependency 주입

2. 인스턴스 생성

3. request 생성 및 response 생성

 

 

그럼 이제 순서대로 자세히 살펴보자.

 

1. dependency 주입

 

API를 사용하려면 Maven 혹은 Gradle 에 dependency를 추가 해줘야 한다.

 

Maven

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

 

Gradle

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-webflux'
}

 

 

2. 인스턴스 생성

 

자 그럼 이제 WebClient를 사용할수 있게 됐으니 인스턴스를 한번 생성해보자.

 

인스턴스를 생성하는 방법에는 여러가지가 있는데 가장 기본적으로 인스턴스를 생성하는 방법은 아래와 같다.

WebClient client = WebClient.create();

 

여기서 인스턴스를 생성할때 해당 WebClient의 BaseUrl(기본 주소)를 설정하고 싶으면 아래와 같이해주면 된다.

 

WebClient client = WebClient.create("주소");

그리고 해당 WebClient의 기본 설정들을 해주고 싶다면 아래와 같이 해주면 된다.

 

WebClient client = WebClient.builder()
  .baseUrl("http://localhost:8080")
  .defaultCookie("cookieKey", "cookieValue")
  .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) 
  .defaultUriVariables(Collections.singletonMap("url", "http://localhost:8080"))
  .build();

위 내용들은 BaseUrl, Cookie, Header, UriVariable을 설정한것이다.

 

나 같은 경우는 api key를 보내야 했기에 아래와 같이 만들었다.

        DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL);
        factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);

        WebClient wc = WebClient.builder().uriBuilderFactory(factory).baseUrl(BASE_URL).build();

나는 인코딩을 해야했기에 위와 같이만들었다. 

WebClient의 인코딩 관련해서는 아래 링크를 통해서 확인해보면 된다.

 

https://wpioneer.tistory.com/222

 

[Spring Boot] WebClient 파라미터 인코딩 하는법

WebClient를 사용해서 그냥 호출하게 되면 인코딩을 하지 않아 API 키가 달라지는 경우가 생길수가 있다. 나같은 경우에 그 문제 때문에 골머리를 앓았는데 아래와 같은 방법으로 해결했다. 일단 Uri

wpioneer.tistory.com

 

그럼 이제 request 생성과 reponse 생성 하는 부분에 대해서 알아보자.

 

3. request 생성 및 response 생성

 

우리가 2번에서 인스턴스를 생성했으니 이제 우리는 request와 response를 만들면 된다.

 

webclient로 할수 있는 요청은 아래와 같다.

GET(조회), POST(등록), PUT(수정), DELETE(삭제)

 

나는 GET을 이용해서 했지만 POST,PUT,DELETE 모두 유사할것이다.

 

일단 소스부터 살펴보자.

        String response = wc.get()
                .uri(uriBuilder -> uriBuilder.path("/getVilageFcst") //uri 생성해주는 부분
                        .queryParam("serviceKey", serviceKey)
                        .queryParam("numOfRows", numOfRows)
                        .queryParam("pageNo", pageNo)
                        .queryParam("dataType", dataType)
                        .queryParam("base_date", base_date)
                        .queryParam("base_time", base_time)
                        .queryParam("nx", nx)
                        .queryParam("ny", ny).build())
                .retrieve() //응답을 받게 하는 부분
                .bodyToMono(String.class) //응답 받을때 값을 하나만 받을 것이다.
                .block(); //동기식으로 응답을 받을것이다.

위 저 소스는 내가 GET요청을 할것이기 때문에 wc.get()으로 했고

 

그 밑에 .uri는 이제 BaseURI 뒤에 만들어질 URI를 만든것이다.

 

일단은 uriBuilder로 uri를 Build하였고 path로는 해당 API 메소드의 이름을 넣어주었다.

 

그리고 밑에 qeuryParam으로는 해당 API를 호출할 조건들을 같이 넣어줬다.

그리고 쿼리들을 다 넣어줬다면 build()를 해서 uri를 만들어줬다.

 

그런 다음에 retrieve()를 통해서 응답을 받게 했다.

 

그리고 여기서 이제 bodyToFlux()냐 bodyToMono()이냐 이 둘중에 하나를 택해야 하는데

만약 응답 받을 값이 여러개이면 bodyToFlux()를 사용하고

응답 받을 값이 한개면 bodyToMono()를 선택해주면 된다.

 

나같은 경우는 응답 받을 값이 한개이기 때문에 bodyToMono()를 했고 응답으로 받을 Class 타입은 

String 이기 때문에 매개변수로 String.class를 입력했다.

 

그리고 나는 이번호출땐 한번의 호출만을 사용할것이기 때문에 .block()을 사용하였다.

 

이렇게 함으로써 정상적으로 API를 호출할수 있게 됐다.

 

그럼 전체 소스를 보자.

package com.wook.weather;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.DefaultUriBuilderFactory;

@SpringBootApplication
public class Application implements CommandLineRunner{

	private final static String BASE_URL = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0";
	private final ApiKey API_KEY;
	
	
	public Application(ApiKey apiKey) {
		this.API_KEY = apiKey;
	}
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
	
    @Override
    public void run( String... args ) throws Exception {
        
        String serviceKey = API_KEY.getApiKey();
        String pageNo = "1";
        String numOfRows = "12";
        String dataType = "JSON";
        String base_date = "20211020";
        String base_time = "2300";
        String nx = "55";
        String ny = "127";

        DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL); //UriBuilder를 생성하는 옵션을 설정하는 DefaultUriBuilderFactory 인스턴스 생성
        factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY); //encoding 모드 설정

        WebClient wc = WebClient.builder().uriBuilderFactory(factory).baseUrl(BASE_URL).build();

        String response = wc.get()
                .uri(uriBuilder -> uriBuilder.path("/getVilageFcst")
                        .queryParam("serviceKey", serviceKey)
                        .queryParam("numOfRows", numOfRows)
                        .queryParam("pageNo", pageNo)
                        .queryParam("dataType", dataType)
                        .queryParam("base_date", base_date)
                        .queryParam("base_time", base_time)
                        .queryParam("nx", nx)
                        .queryParam("ny", ny).build())
                .retrieve().bodyToMono(String.class).block();

        System.out.println(response);
        System.out.println(API_KEY.getApiKey());
        
    }
    
}

 

반응형