[Spring] 외부 API 연동하기 (RestTemplate vs. WebClient vs. OpenFeign)

2025. 10. 5. 15:27·Spring

들어가며 

보통 API 호출은 보통 클라이언트에서 일어나게 되지만, 프로젝트를 진행하면서 이제는 백엔드 서버에서 다른 서버로 API를 호출해야 하는 경우가 생겼다. 이번 포스팅에서는 스프링에서 외부 API를 호출하는 대표적인 방법인 RestTemplate, WebClient, OpenFeign에 대해서 알아보려고 한다. 


1. RestTemplate 

RestTemplate은 Spring에서 제공하는 전통적인 HTTP 클라이언트로 다양한 HTTP 메서드를 사용하여 원격 서버와 통신할 수 있다. 이 방식은 동기 방식으로, 호출한 스레드는 응답이 올 때까지 대기한다. 이는 높은 트래픽 상황에서는 스레드가 묶여 성능 문제가 생길 수 있다. RestTemplate 자체가 deprecated 된 것은 아니지만, Spring에서는 WebClient 사용을 권장한다. 

 

아래와 같이 먼저 RestTemplate Bean을 등록한다. RestTemplateBuilder를 사용하면 타임아웃 설정 등을 쉽게 적용할 수 있다. 이 타임아웃을 설정하는 이유는 기본값은 무한정 기다리도록 되어 있기 때문에 장애 상황에서 서비스 전체가 느려지는 문제가 생기기 때문이다. 

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
           .setConnectTimeout(Duration.ofSeconds(3)) // 서버에 연결 시도 제한
           .setReadTimeout(Duration.ofSeconds(5))    // 응답 대기 제한
           .build();
}

 

그리고 서비스에서 RestTemplate을 주입 받아 사용한다. 

@Service
public class UserService {
    private final RestTemplate restTemplate;

    public UserService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public User getUser(String id) {
        String url = "https://api.example.com/users/{id}";
        
        ResponseEntity<User> response =
                restTemplate.getForEntity(url, User.class, id);

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

2. WebClient

RestTemplate의 후속 개념으로 Spring WebFlux에 포함되나, WebFlux를 사용하지 않아도 WebClient만 단독 사용도 가능하다.

일반적인 RestTemplate은 요청을 보내면 응답이 올 때까지 스레드가 기다리는 블로킹 방식이지만, WebClient는 기다리면서 스레드를 잡아두지 않고 다른 일을 할 수 있게 해주는 논블로킹 방식이다. 그래서 동시에 많은 요청을 처리해야 하는 환경에서 훨씬 유리하다. 

 

WebClient는 원래 비동기 + 논블로킹 방식이 기본이지만, `.block()` 을 사용하면 응답을 받을 때까지 기다리기 때문에 RestTemplate처럼 동기 방식으로 동작하기도 한다. 

 

WebClient는 리액티브 프로그래밍 개념을 사용하기 때문에, 응답을 Mono/Flux 형태로 돌려준다. WebClient가 Mono/Flux를 사용하는 이유는 Reactor라는 리액티브 라이브러리를 기반으로 만들었기 때문이다. 

Reactor는 리액티브 프로그래밍을 위한 라이브러리로, Mono는 0-1개의 결과 (단일 응답), Flux는 0-N개의 결과 (리스트, 스트림)

 

일단 WebClient Bean을 등록한다. WebClient 객체를 생성하기 위한 빌더 패턴을 통해 기본 url을 지정하여 WebClient 인스턴스를 생성한다. 

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient() {
        return WebClient.builder()
                .baseUrl("https://jsonplaceholder.typicode.com")
                .build();
    }
}

 

WebClient를 동기 호출 방식으로 작성한 예제이다. 응답을 받아와 응답 본문을 PostResponse 타입으로 Mono 형태로 받는다. 마지막에 `.block()` 를 통해서 응답이 올 때까지 스레드가 기다리는 동기 방식으로 동작한다. 

@Service
public class PostService {

    private final WebClient webClient;

    public PostService(WebClient webClient) {
        this.webClient = webClient;
    }

    public PostResponse getPostById(Long id) {
        return webClient.get()
                .uri("/posts/{id}", id)
                .retrieve()
                .bodyToMono(PostResponse.class)
                .block();   // 동기 방식
    }
}

public class PostResponse {
    private Long id;
    private Long userId;
    private String title;
    private String body;

    // getters, setters
}

 

비동기 방식으로 작성한 예제이다. 뒤에 `.block()` 을 호출하지 않아 Mono 객체가 그대로 변환된다. 

public Mono<PostResponse> getPostAsync(Long id) {
    return webClient.get()
            .uri("/posts/{id}", id)
            .retrieve()
            .bodyToMono(PostResponse.class);
}

3. OpenFeign 

WebClient와 RestTemplate은 직접 메서드를 호출하고 URI를 작성해야 한다. 하지만 Feign은 인터페이스만 만들면 자동으로 HTTP 요청 코드가 생성되는 특징을 가진다. 복잡한 코드를 전부 자동으로 해준다 !  `@FeignClient` 만 붙이면 사용이 가능하며 Spring Cloud와 강력하게 통합되어 있다. API가 많을 때, WebClient와 RestTemplate 코드는 금방 복잡해지만 Feign는 API 하나에 인터페이스 메서드 하나로 구조가 깔끔하다는 특징이 있다. 그러나 완전한 논블로킹 기반은 아니며 내부적으로는 여전히 blocking I/O 기반이 기본이다. 

 

일단 의존성을 추가해야 한다. 

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}

 

Feign 설정을 활성화한다. Feign 인터페이스를 스캔하고 Bean으로 등록한다. 

@EnableFeignClients
@SpringBootApplication
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class, args);
    }
}

 

Feign Client 인터페이스를 작성한다. `@FeignClient(name, url)` 는 외부 API 호출을 담당한다는 의미를 갖는다. 

@FeignClient(name = "jsonPlaceholder", url = "https://jsonplaceholder.typicode.com")
public interface JsonPlaceholderClient {

    @GetMapping("/posts/{id}")
    PostResponse getPostById(@PathVariable Long id);

    @PostMapping("/posts")
    PostResponse createPost(@RequestBody PostRequest request);
}

 

그리고 별도의 WebClient나 RestTemplate 작성이 필요 없다. 단순히 프록시처럼 인터페이스 메서드를 호출하면 API 요청이 날아가고, 응답이 DTO로 바인딩 된다. 

@Service
public class PostService {

    private final JsonPlaceholderClient client;

    public PostService(JsonPlaceholderClient client) {
        this.client = client;
    }

    public PostResponse getPost(Long id) {
        return client.getPostById(id);
    }

    public PostResponse createPost(PostRequest request) {
        return client.createPost(request);
    }
}

public class PostRequest {
    private Long userId;
    private String title;
    private String body;
}

public class PostResponse {
    private Long id;
    private Long userId;
    private String title;
    private String body;
}

 

'Spring' 카테고리의 다른 글

[Spring] 데이터 유효성 검증 (Validation) 이해하기  (0) 2025.11.04
[Spring] DTO 활용 패턴 - toEntity(), from() 정적 팩토리 메서드  (0) 2025.10.13
[Spring] N+1 문제  (0) 2025.10.03
[Spring] 객체지향 쿼리 언어  (0) 2025.10.02
[Spring] 즉시 로딩과 지연 로딩  (0) 2025.09.21
'Spring' 카테고리의 다른 글
  • [Spring] 데이터 유효성 검증 (Validation) 이해하기
  • [Spring] DTO 활용 패턴 - toEntity(), from() 정적 팩토리 메서드
  • [Spring] N+1 문제
  • [Spring] 객체지향 쿼리 언어
erika0915
erika0915
백엔드 개발자가 되고 싶어요 .
  • erika0915
    erikoding
    erika0915
  • 전체
    오늘
    어제
    • 분류 전체보기 (78)
      • 프로젝트 (13)
        • 끼니콩 (3)
        • 덕메랑 (3)
        • handDoc (7)
        • Haeil (0)
      • Java (9)
        • 클린코더스 (0)
      • Spring (30)
      • Redis (3)
      • CS (7)
        • 운영체제 (3)
        • 컴퓨터구조 (0)
        • 네트워크 (4)
      • DevOps (2)
      • 코딩테스트 (0)
      • Tech (14)
        • TDD (1)
        • 정리 (5)
        • 우테코 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    docker
    파인튜닝
    코드레빗
    지라
    java
    몽고디비
    STT
    레디스
    CoolSMS
    jira
    깃
    git
    Spring
    redis
    Network
    springboot
    자바
    스프링
    MongoDB
    운영체제
    github
    스프링부트
    promtail
    AI
    coderabbit
    깃허브
    도커
    네트워크
    OS
    TDD
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
erika0915
[Spring] 외부 API 연동하기 (RestTemplate vs. WebClient vs. OpenFeign)

티스토리툴바