WebClient 사용해 외부 API 호출하기

o_z·2024년 3월 12일
post-thumbnail

추천 여행지, 일정을 띄워줄 때 해당 지역의 대표 이미지가 들어간다는 요구사항이 추가됐다.

모든 지역마다 대표 이미지를 가져와서 띄우고자 stock image API 중 pixabay를 사용하고자 한다.


Spring에서 외부 API 호출하는 방법

대표적으로 RestTemplate과 WebClient 두 가지가 있다.

RestTemplate

  • 멀티 스레드, 블로킹 방식
  • 통신을 단순화 하고 RESTful 원칙을 지킴
  • 비동기화가 불가능
  • 락이나 병목 현상 발생 시 가용 가능한 스레드 수가 하락하고, 전체 서비스가 느려짐

WebClient

  • 싱글 스레드, 논블로킹 방식
    => 논블로킹으로 네트워킹의 병목 현상 줄이고 성능 향상
  • 비동기화 가능함
  • JSON, XML 응답 받기가 쉬움

이 중 나는 WebClient를 사용하기로 했다. 스프링 5.0부터는 WebClient가 권장되기도 하고 나중에 RestTemplate이 deprecated 된다는 소식이 있다 해서 WebClient를 선택했다.


WebClient로 외부 API 호출하기

일단 pixabay API key는 pixabay의 API 카테고리 가면 쉽게 발급 받을 수 있다. 발급 받은 API key는 보호되어야 하는 정보이므로 application.yml 파일에 작성했다.

먼저 WebClient는 Spring WebFlux를 사용하므로 의존성을 추가한다.

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

WebFlux?

  • Client, Server에서 reactive 스타일의 애플리케이션 개발을 도와주는 Spring 모듈이고 Spring 5에서 새로 추가되었다.
  • 적은 스레드로 자원을 효율적으로 사용할 수 있다는 장점이 있다.

WebClient를 생성하는 데에는 두 가지 방법이 있다.

  1. WebClient.create(baseURL);
  2. WebClient.builder().build();

create()는 WebClient를 기본 옵션으로 생성하는 메서드고, builder()는 헤더, 쿠키, url 커스텀 등 여러 옵션을 붙여서 생성할 수 있다. 나는 일단 옵션이 필요하지 않으므로 create()를 사용했다.

WebClient webClient = WebClient.create(baseURL);

나는 "{국가} {지역}" 키워드로 검색한 이미지 결과를 사용해야 한다. 따라서 pixabay API의 get을 호출하면 된다.

원하는 결과를 위해 uri에 넣어야 할 3개 parameter도 uri()를 사용해 넣어주었다.

  1. q : 검색할 키워드
  2. lang : 검색 언어
  3. key : pixabay에서 발급 받은 API key

WebClient의 응답 받는 방식은 retrive(), exchange()가 있다.

  1. retrive() : ClientResponse의 body를 받고 사용자가 사용할 수 있도록 미리 만든 개체를 제공하는 간단한 메서드
  2. exchange() : ClientResponse를 상태값, 헤더와 함께 가져오고 세세한 컨트롤이 가능한 메서드 (deprecated 됨)

exchange()의 경우 세부적인 response 컨트롤이 가능한 만큼 response에 대해 모든 처리를 직접 해야하므로 메모리 누수 가능성이 발생한다고 한다. 해당 이유로 retrive()가 권장되기에 내 코드에서도 retrive()를 사용했다.

bodyToMono()는 가져온 body를 Mono 객체로 바꿔주는 메서드이다. Mono 객체의 경우 0~1개의 결과를 처리하는 객체로, 응답 바디를 특정 클래스로 바인딩 할 때 사용된다. 나는 JSON 결과를 String으로 받아서 하나의 필드만 뽑아 사용할 것이기 때문에 bodyToMono(String.class)로 호출했다.

block()은 비동기 non-blocking 방식으로 Mono 객체를 동기식 데이터 객체로 받아오기 위해 사용되는 메서드이다. API를 호출한 결과 응답이 올 때까지 대기하기 위해 사용했다.

String response = webClient.get()
			.uri(uriBuilder -> uriBuilder
				.queryParam("q", searchKeyword)
				.queryParam("lang","ko")
				.queryParam("key", apiKey)
				.build())
			.retrieve()
			.bodyToMono(String.class)
			.block();

그렇게 생성된 호출 코드 전체는 아래와 같다.

private String getLocateImage(Country country, City city) {
		String url = "https://pixabay.com/api/";
		String searchKeyword = country.toString().concat(" ").concat(city.toString());

		// WebClient 생성
		WebClient webClient = WebClient.create(url);
		// paprameter 추가해 get 호출
        String response = webClient.get()
			.uri(uriBuilder -> uriBuilder
				.queryParam("q", searchKeyword)
				.queryParam("lang","ko")
				.queryParam("key", apiKey)
				.build())
			.retrieve()
			.bodyToMono(String.class)
			.block();
	}

이렇게 하면 searchKeyword로 검색한 이미지 결과들이 Json 형태의 String으로 response에 담긴다.

이제 response를 파싱해 원하는 필드만 뽑아 사용하면 끝! (Json 파싱은 다음에 쓰는걸로..)


참고
https://blog.naver.com/chgy2131/222982836335
https://gngsn.tistory.com/154
https://velog.io/@rnqhstlr2297/Spring-Webflux%EC%99%80-WebClient

profile
트러블슈팅과 구현기를 위주로 기록합니다-

0개의 댓글