우당탕탕

스프링 외부 API 호출 방법 비교: RestTemplate, WebClient, FeignClient, RestClient 본문

Tech/Spring

스프링 외부 API 호출 방법 비교: RestTemplate, WebClient, FeignClient, RestClient

모찌모찝 2025. 4. 14. 18:00
스프링 외부 API 호출 방법 비교: RestTemplate, WebClient, FeignClient, RestClient

 

이번 포스팅에서는 스프링에서 외부 API ( OpenApi )를 호출하는 대표적인 방법인 RestTemplate, WebClient, FeignClient, RestClient비교해 보려고 합니다. 각각의 특징과 장단점을 먼저 살펴보고 어떤 상황에서 어떤 방식이 제일 효율적인지 알아보겠습니다.

외부 API 호출 비교분석

1. RestTemplate

RestTemplate스프링 3.0부터 제공된 HTTP 클라이언트로, 간단한 API 호출을 위해 많이 사용되었습니다. 사용법 또한 간단하여 많이 사용해 왔지만 스프링 5.0 이후로는 더 이상 새로운 기능이 추가되지 않고 유지보수만 진행 중인 상태입니다.
특징으로는 동기적(Blocking)방식으로 동작하며 JSON과 XML 등 다양한 데이터 변환을 지원합니다. 사용법이 간단하여 많이 사용되었었습니다. 하지만 Blocking I/O 기반으로 동시 처리 성능이 낮은 편입니다.

👨‍💻 블로킹( Blocking )이란?
- 작업이 끝날 때까지 스레드가 대기 상태로 점유되는 방식으로, 단순하지만 동시 처리에 비효율적입니다.

예시코드

@Service
public class RestTemplateExample {

    private final RestTemplate restTemplate;

    // RestTemplate 객체 생성
    public RestTemplateExample() {
        this.restTemplate = new RestTemplate();
    }

    // 외부 API 호출 메서드
    public String callApi() {
        // 호출할 API URL
        String url = "https://api.example.com/data";

        // HTTP 요청 헤더 설정
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 요청 바디에 전달할 데이터 설정
        Map<String, Object> requestBody = Map.of("name", "John", "age", 30);

        // 요청 엔티티 생성 (헤더와 바디 포함)
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);

        // POST 요청을 보내고 응답을 받음
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);

        // 응답 본문 반환
        return response.getBody();
    }
}

2. WebClient

WebClient는 스프링 5.0에서 도입된 리액티브 웹 클라이언트로, 비동기(Non Blocking) 방식의 HTTP 요청을 지원합니다. RestTemplate과 다르게 Non Blocking이 가능한 것이 장점입니다.
특징으로는 함수형 API제공으로 유연한 요청 구성이 가능하며, 리액티브 프로그래밍 기반으로 동작하고 비동기 처리 및 스트림 처리에 강점을 가집니다. 보통 높은 동시성을 요구하는 작업이나 대규모 트래픽 처리에 사용됩니다. 하지만 RestTemplate과 다르게 학습시간이 조금 필요합니다. ( 기존 동기방식 코드와 혼용 시에 복잡도가 증가할 수 있습니다 )

👨‍💻 논블로킹( Non Blocking )이란?
- 작업이 끝날 때까지 기다리지 않고 다른 작업을 계속할 수 있는 방식입니다. ( ex: 파일 다운로드 중에도 다른 프로그램을 실행할 수 있는 느낌. )

👨‍💻 리액티브 웹 클라이언트란?
- 리액티브 웹 클라이언트란 WebClient와 같은 클라이언트로, 데이터를 기다리지 않고 요청을 보내며, 결과가 준비되면 이를 처리하는 비동기 방식의 HTTP 클라이언트입니다.

예시코드

@Service
public class WebClientExample {

    private final WebClient webClient;

    // WebClient 객체 생성 및 기본 설정
    public WebClientExample() {
        this.webClient = WebClient.builder()
                .baseUrl("https://api.example.com") // 기본 URL 설정
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) // 기본 헤더 설정
                .build();
    }

    // 비동기 방식으로 외부 API 호출
    public Mono<String> callApi() {
        return webClient.post() // POST 요청 설정
                .uri("/data") // 호출할 엔드포인트 설정
                .bodyValue(Map.of("name", "John", "age", 30)) // 요청 바디 데이터 설정
                .retrieve() // 응답 처리 시작
                .bodyToMono(String.class); // 응답 데이터를 Mono로 변환하여 반환
    }

    // 동기 방식으로 외부 API 호출 (block 사용)
    public String callApiSynchronously() {
        return webClient.post() // POST 요청 설정
                .uri("/data") // 호출할 엔드포인트 설정
                .bodyValue(Map.of("name", "John", "age", 30)) // 요청 바디 데이터 설정
                .retrieve() // 응답 처리 시작
                .bodyToMono(String.class) // 응답 데이터를 Mono로 변환
                .block(); // Mono를 블로킹하여 동기적으로 결과 반환
    }
}

3. FeignClient

FeignClientNetflix OSS에서 제공하는 선언적 HTTP 클라이언트로, 인터페이스 기반으로 API 호출을 정의할 수  있습니다. Spring Cloud와 통합되어 마이크로서비스 아키텍처(MSA) 환경에서 자주 사용됩니다.
특징으로는 인터페이스 선언만으로 구현체가 자동생성되며, Spring Cloud와 연계가 잘 되어있습니다. 또한 인터페이스 형식으로 코드 가독성이 뛰어나고 유지보수가 용이합니다. 서비스 디스커버리( Eureka [유레카] 등)와 연동이 가능하며 Circuit Breaker(서킷 브레이커)와 같은 장애 복구 패턴 적용도 가능합니다. 하지만 RestTemplate과 동일하게 Blocking I/O기반으로 동시처리 성능이 낮으며 복잡한 요청 처리가 어려울 수 있습니다. 

👨‍💻 서비스 디스커버리란?
- 서비스 이름만으로 위치(IP 주소와 포트)를 찾아주는 기능으로, 동적으로 변하는 환경에서 유용합니다.

👨‍💻 서킷 브레이커란?
- 외부 서비스 장애 시 시스템 전체 장애를 방지하기 위해 요청을 제한하거나 빠르게 실패 처리하는 패턴입니다.

예시코드

// FeignClient 인터페이스 정의 (외부 API와 연동)
@FeignClient(name = "example-api", url = "https://api.example.com")
public interface ExampleApiClient {

    @PostMapping("/data") // 호출할 엔드포인트와 HTTP 메서드 정의
    String callApi(@RequestBody Map<String, Object> requestBody); // 요청 바디를 전달하고 응답을 받음
}

@Service
@RequiredArgsConstructor
public class FeignClientExample {

    private final ExampleApiClient exampleApiClient; // FeignClient 인터페이스 주입

    public String callApi() {
        Map<String, Object> requestBody = Map.of("name", "John", "age", 30); // 요청 바디 데이터 생성

        return exampleApiClient.callApi(requestBody); // FeignClient를 통해 API 호출 및 응답 반환
    }
}

4. RestClient

RestClient는 스프링 6.1에서 새롭게 도입된 HTTP 클라이언트로 RestTemplate의 현대적인 대안으로 나왔습니다. 기존의 동기적 방식과 유사하면서도 더 깔끔한 API를 제공합니다. 
특징으로는 선언적이고 직관적인 API를 제공하며 Spring MVC환경에 최적화되어있습니다. RestTemplate보다 간결하며 기존 RestTemplate개발자들에게 친숙한 면이 존재합니다. 
( 추가 의존성 없이 스프링 코어에 포함되어 있는 장점도 있습니다 ) 

예시코드

@Service
public class RestClientExample {

    private final RestClient restClient;

    // RestClient 객체 생성 및 기본 설정 (스프링 6.1 이상)
    public RestClientExample() {
        this.restClient = RestClient.builder()
                .baseUrl("https://api.example.com") // 기본 URL 설정
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) // 기본 헤더 설정
                .build();
    }

    public String callApi() {
        return restClient.post() // POST 요청 설정
                .uri("/data") // 호출할 엔드포인트 설정
                .body(Map.of("name", "John", "age", 30)) // 요청 바디 데이터 설정
                .retrieve() // 응답 처리 시작
                .body(String.class); // 응답 데이터를 문자열로 반환
    }
}

5. 성능 비교 

방식 I/O 모델 장점 단점
RestTemplate Blocking 간단하고 직관적 높은 동시성 환경에서 성능 저하
WebClient Non-blocking 높은 확장성과 효율적인 리소스 사용 리액티브 프로그래밍 학습 필요
FeignClient Blocking 선언적 인터페이스로 가독성 및 유지보수 용이 복잡한 요청 처리에는 한계
RestClient Blocking 현대적이고 간결한 설계 최신 스프링 버전 필요

6. 상황별 선택 가이드 

API 호출 방식은 서비스 성능과 밀접하게 연결되어 있습니다. 어떤 호출 방식을 선택하냐에 따라 성능이 크게 차이 날 수 있으므로 환경에 맞는 방식을 선택해야 합니다.

  • 소규모 프로젝트
    • RestTemplate 또는 RestClient : 간단하고 빠르게 구현이 가능
  • 대규모 트래픽 처리 프로젝트
    • WebClient : 논블로킹(Non Blocking) I/O 기반으로 효율적인 리소스 관리가 가능
  • 마이크로서비스 아키텍처(MSA)
    • FeignClient : 서비스 디스커버리 및 장애 복구 패턴 적용에 유리
  • 레거시 시스템 통합
    • RestTemplate : 기존 코드와의 호환성이 중요할 때 적합

이번 포스팅에서는 외부 API를 호출하는 다양한 방법을 소개하고 비교해 보았습니다. 각 방식은 고유의 장단점을 가지고 있으며, 프로젝트 요구사항에 맞게 선택하는 것이 중요합니다. 개인적으로 최신 프로젝트의 경우 WebClient나 RestClient를 사용하는 것을 추천합니다. 

Comments