API 호출은 대부분의 애플리케이션 개발에 기본이 되는 작업입니다. 실제로 업무에서 RestTemplate을 사용한 경험이 있는데요. 요새는 다른 방식도 이용한다고 해서 경험해볼 겸 이렇게 글을 작성해봤습니다. 이 게시글에서는, 스프링 부트 프로젝트에서 API 호출을 할 때 사용하는 RestTemplate, WebClient, 그리고 Feign을 비교하고 간단한 예제 코드를 제공합니다.
본 글에서는 https://open.er-api.com/v6/latest에서 한국의 환율을 조회하는 방식으로 예제 코드를 작성했습니다.
1. RestTemplate
RestTemplate는 스프링 프레임워크에서 HTTP 요청을 손쉽게 수행할 수 있는 도구입니다. RestTemplate은 동기식 호출을 사용하며, 아래에 예제 코드를 볼 수 있습니다.
RestTemplate rt = new RestTemplate();
Map<String, Map<String, Double>> res = rt.getForObject("https://open.er-api.com/v6/latest", Map.class);
System.out.println(res.get("rates").get("KRW"));
저는 업무에서 API를 호출할때 Basic Auth 가 필요한 경우가 꽤 있었어요. 따라서 그때의 기억을 되살려서 임의의 코드를 작성해보겠습니다.
String url = "localhost:8080"
String auth = "id:password";
String base64Creds = Base64.getEncoder().encodeToString(auth.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
HttpEntity request = new HttpEntity(headers);
ResponseEntity<ResponseDTO> response = new RestTemplate().exchange(url, HttpMethod.GET, request, ResponseDTO.class);
Basic Auth 자체가 Basic Base64Encode(id:password) 의 형태이기에 그에 맞춰서 문자열을 생성해주는 부분이 필요합니다. 저도 그렇고 대부분의 분들이 이런 방식으로 RestTemplate에서 Basic Auth 정보를 넘겨주고 있습니다.
참고로 RestTemplate에서 헤더 정보를 편집해서 API 호출을 해야되는 경우에는 exchange 메서드를 사용해주셔야 합니다.
2. WebClient
WebClient는 리액티브 프로그래밍에 기반한 스프링 5에서 새롭게 도입된 비동기 네트워크 통신 클라이언트입니다. 이를 사용하면 비동기 방식으로 API 호출을 할 수 있습니다. WebClient를 사용하기 위해서는 spring-boot-starter-webflux 의존성을 추가해줘야 합니다.
WebClient client = WebClient.create("https://open.er-api.com");
Map<String, Map<String, Double>> res2 = client.get().uri("/v6/latest")
.retrieve().bodyToMono(Map.class).block();
System.out.println(res2.get("rates").get("KRW"));
그렇다면 WebClient 에서는 Basic Auth를 어떻게 구현할까요?
WebClient client2 = WebClient.builder().baseUrl("https://open.er-api.com")
.defaultHeaders(header -> header.setBasicAuth(id, password)).build();
Map<String, Map<String, Double>> res3 = client2.get().uri("/v6/latest").retrieve().bodyToMono(Map.class)
.block();
System.out.println(res3.get("rates").get("KRW"));
일반 API 호출 예시에서는 create 메서드를 사용했습니다. create() 는 builder().baseUrl().build()랑 동일합니다. Header의 편집이 필요해서 이렇게 전개된 방식으로 접근했습니다.
그렇다면 create()를 쓸때는 Basic Auth 정보를 추가해줄 수 없을까요??
WebClient client2 = WebClient.builder().baseUrl("https://open.er-api.com").defaultHeaders(null).build();
Map<String, Map<String, Double>> res3 = client2.get().uri("/v6/latest")
.headers(headers -> headers.setBasicAuth(id, password))
.retrieve().bodyToMono(Map.class).block();
System.out.println(res3.get("rates").get("KRW"));
retrive로 값을 가져오기 전에 header를 붙여줄 수 있다고 합니다.
조금 더 편한 방식으로 사용하시면 되겠네요 :)
3. Feign
Feign은 선언적 HTTP 클라이언트로, API 호출에 사용 가능한 또 다른 유용한 도구입니다. Feign은 인터페이스를 사용하여 API 연결을 추상화하고 읽기 쉽게 만듭니다. spring-cloud-starter-openfeign 의 의존성을 추가해줘야 사용이 가능합니다.
implementation platform("org.springframework.cloud:spring-cloud-dependencies:2022.0.2")
implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
저는 위처럼 gradle에 추가해줬습니다. 그냥 spring-cloud-starter-openfeign 만 쓰면 디펜던시를 찾아오지 못하더라구요. 본인의 spring boot 버전에 맞춰서 환경을 세팅해주셔야 됩니다. Release 버전은 아래 사진을 참고해주세요.
Feign을 사용하기 위해서는 추가 설정이 필요합니다.
@SpringBootApplication
@EnableFeignClients
root 프로젝트 main 클래스에 @EnableFeignClients 를 추가해줘야합니다. 이게 있어야 @FeignClient 를 찾아 구현체를 만들어 줍니다.
RateClient.java
@FeignClient(name = "rateClient", url = "https://open.er-api.com")
public interface RateClient {
@GetMapping(value = "/v6/latest")
ApiResponse getExchangeRates();
}
ApiResponse.java
public class ApiResponse {
private String result;
private Map<String,Double> rates;
public Map<String, Double> getRates() {
return rates;
}
}
Controller나 서비스에서 호출
System.out.println(rClient.getExchangeRates().getRates().get("KRW"));
이런 구성으로 작성하시면 됩니다. 제가 위에서 RestTemplate이나 WebClient를 사용할때는 Response 로 넘어온 JSON 데이터를 객체에 담지 않고 바로 사용했습니다. 그래서 비교적 구현하는 코드가 더 짧아보이네요. 쟤네도 동일하게 설정해주시면 Feign쪽이 더 직관적으로 다가올 수 있습니다. Feign도 Map에 담아서 바로 쓰고 싶었는데 마땅한 방법을 찾지 못했습니다...
Feign를 이용할때는 Basic Auth를 어떻게 구현할까요?
아래와 같이 Configuration을 등록해주면 됩니다.
public class BasicAuthConfiguration {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("id", "password");
}
}
그러고 FeignClient에 configuration 정보를 등록해주면 Basic Auth를 정상적으로 쓸 수 있습니다.
@FeignClient(name = "rateClient", url = "https://open.er-api.com", configuration = BasicAuthConfiguration.class)
public interface RateClient {
@GetMapping(value = "/v6/latest")
ApiResponse getExchangeRates();
}
4. 결론
Spring Boot에서 API 호출을 할 때 사용하는 RestTemplate, WebClient, 그리고 OpenFeign 중 어떤 것을 선택할까요?
몇 가지 고려 사항들이 있습니다
- RestTemplate: 동기식 호출에 적합한 클래식한 방법을 선호하는 경우 사용하세요.
- WebClient: 리액티브 프로그래밍에 적합합니다. Spring 에서 권장하는 모던한 방식이라고 합니다.
- Feign: 코드 가독성이 중요하거나, 선언적 방식의 인터페이스를 사용하는 것이 편리하다고 생각하는 경우 사용하세요.
프로젝트의 요구사항, 성능 요구 사항 및 개발자의 선호도에 따라 여러 방법 중 하나를 선택하여 적용할 수 있습니다. 각 방법의 장단점을 잘 이해하고, 프로젝트에 가장 적합한 도구를 사용하시길 바랍니다!
이 글이 도움이 되셨길 바랍니다.
'web > spring&spring boot' 카테고리의 다른 글
[Spring] HTTPS 활성화 (0) | 2024.02.12 |
---|---|
[Spring] Mybatis의 snake case를 camel case로 자동 변환하기 (0) | 2024.01.27 |
[Spring Boot] @Component에 대한 이해 (0) | 2023.04.03 |
[Spring Batch] Spring Batch의 장점 (0) | 2022.02.26 |
[Spring] REST API 구현 (0) | 2021.11.07 |