💬 외부 API 호출, RestTemplate vs WebClient vs RestClient 중 무엇을 선택할까?
스프링 부트 기반 음식 주문 플랫폼에서 네이버 지오코딩 API를 연동하며 겪은 기술 선택 과정
1. 프로젝트 배경 및 요구사항
1-1. 프로젝트 개요
Stack: Spring Boot, Spring Data JPA, QueryDSL, PostgreSQL
Domain: address (주소 관리 도메인)
1-2. 해결해야 할 문제
사용자가 가게를 등록할 때, "서울시 강남구 테헤란로 123"처럼 텍스트로 입력한 주소를:
- 정확한 좌표(위도/경도)로 변환해야 함 (배달 거리 계산용)
- 도로명/지번 주소를 정형화해야 함 (DB 저장 및 검색 최적화)
- 네이버 지도 Geocoding API를 외부 HTTP 호출로 연동 필요
1-3. 기술적 요구사항
- 사용자 요청에 즉시 응답 필요 (동기 처리)
- 단일 API 호출 (복잡한 비동기 플로우 불필요)
- Spring MVC 기반 프로젝트 (WebFlux 미사용)
- 코드 유지보수성 및 팀원 이해도 고려
2. 비교
스프링 생태계에서 사용할 수 있는 3가지 주요 HTTP 클라이언트를 비교했다
| 구분 | RestTemplate | WebClient | RestClient |
|---|---|---|---|
| 도입 버전 | Spring 3.x | Spring 5.x | Spring 6.1 |
| 동작 방식 | 동기 (Blocking) | 비동기 (Non-blocking) | 동기 (Blocking) |
| 리턴 타입 | 객체 / ResponseEntity |
Mono, Flux |
객체 / ResponseEntity |
| 학습 곡선 | 낮음 | 중간~높음 | 낮음 |
| 성능 | 단일 요청에 적합 | 대규모 병렬 요청, Reactive Stack | 단순 REST 호출 |
| 의존성 | spring-web |
spring-webflux추가 필요 |
spring-web |
| 상태 | ⚠️ 유지보수 전용 | ✅ Reactive 환경용 | ✅ 신규 표준 (Spring 6+) |
3. 기술별 상세 분석
3-1. RestTemplate
Spring 3.x ~ Spring 5.x에서 가장 널리 사용되던 HTTP 클라이언트
단순하고 직관적이지만 Spring 6 이후 비권장
단점
- 완전 동기(Blocking) 방식으로 대규모 트래픽에 비효율적
- Fluent API(메서드 체이닝) 부재로 코드 가독성 떨어짐
- 에러 처리 및 타임아웃 설정이 복잡
RestTemplate restTemplate = new RestTemplate();
String url = "<https://api.example.com/users/1>";
// 단순하지만 구식 API
UserResponse response = restTemplate.getForObject(url, UserResponse.class);
결론: 신규 프로젝트에는 부적합 ❌
3-2. WebClient
Spring 5 WebFlux와 함께 등장한 비동기/논블로킹 클라이언트
Reactive Streams(Mono, Flux) 기반
장점:
- 대규모 병렬 요청 처리에 최적 (MSA, 실시간 스트리밍)
- Fluent API로 유연한 요청 조합 가능
단점:
spring-boot-starter-webflux의존성 추가 필요- 단순 REST 호출에는 과도한 복잡성 (Overkill)
.block()으로 강제 동기화 시 안티패턴
WebClient webClient = WebClient.builder()
.baseUrl("<https://api.example.com>")
.build();
// Reactive 타입 반환
Mono<UserResponse> responseMono = webClient.get()
.uri("/users/1")
.retrieve()
.bodyToMono(UserResponse.class);
// ❌ 안티패턴: 동기 프로젝트에서 강제 블로킹
UserResponse user = responseMono.block();
결론: MVC 프로젝트에서 단순 API 호출에는 부적합 ❌
3-3. RestClient
Spring 6.1 (Spring Boot 3.2) 부터 도입된 최신 HTTP 클라이언트
RestTemplate의 현대적 대체이자 WebClient의 간결한 빌더 스타일을 계승
장점:
spring-web에 포함되어 별도 의존성 불필요- Fluent API(메서드 체이닝) 으로 가독성 우수
- 동기 방식으로 디버깅 및 에러 추적 용이
- 타임아웃, 에러 핸들링 등 현대적 기능 지원
단점:
- Spring Boot 3.2+ 미만 버전에서는 사용 불가 (버전 제약)
RestClient restClient = RestClient.builder()
.baseUrl("<https://api.example.com>")
.defaultHeader("Authorization", "Bearer token")
.build();
// 직관적이고 간결한 동기 호출
UserResponse user = restClient.get()
.uri("/users/1")
.retrieve()
.body(UserResponse.class);
결론: MVC 기반 프로젝트에서 최적 선택 ✅
4. 최종 구현:RestClient
RestClient를 최종 선택
4-1. 선택이유
| 조건 | RestClient 적합성 |
|---|---|
| 즉시 응답 필요 | ✅ 동기 방식으로 요청-응답이 명확 |
| 단일 API 호출 | ✅ 복잡한 비동기 플로우 불필요 |
| Spring MVC 기반 | ✅ WebFlux 의존성 추가 없이 사용 가능 |
| 팀 협업 | ✅ 낮은 학습 곡선, 직관적 코드 |
| Spring 공식 권장 | ✅ RestTemplate의 현대적 대체재 |
4-2. 최종 코드
초기화 (빌더 패턴)
@Service
public class NaverMapService {
private final RestClient restClient;
public NaverMapService(
@Value("${naver.client-id}") String clientId,
@Value("${naver.client-secret}") String clientSecret
) {
this.restClient = RestClient.builder()
.baseUrl("<https://maps.apigw.ntruss.com>")
.defaultHeader("X-NCP-APIGW-API-KEY-ID", clientId)
.defaultHeader("X-NCP-APIGW-API-KEY", clientSecret)
.build();
}
API 호출 메서드
public Page<AddressResponseDto> getAddress(String address, Pageable pageable) {
// 1. 네이버 Geocoding API 호출
NaverAddressResponse response = restClient.get()
.uri(uriBuilder -> uriBuilder
.path("/map-geocode/v2/geocode")
.queryParam("query", address) // 사용자 입력 주소
.build())
.retrieve()
.body(NaverAddressResponse.class);
// 2. 응답 데이터를 DTO로 변환
List<NaverAddress> addresses = response.addresses();
// 3. Spring Data Page로 페이징 처리
Page<NaverAddress> pagedAddresses = new PageImpl<>(
addresses,
pageable,
addresses.size()
);
// 4. 최종 응답 DTO 반환
return pagedAddresses.map(AddressResponseDto::from);
}
}
5. 결론
5-1. Spring HTTP 클라이언트 선택 가이드
| 상황 | 권장 기술 |
|---|---|
| Spring Boot 3.2+ MVC 프로젝트 | ✅ RestClient |
| Reactive Stack (WebFlux) | ✅ WebClient |
| 대규모 병렬 API 호출 | ✅ WebClient (비동기) |
| 레거시 유지보수 | ⚠️ RestTemplate (신규 개발 X) |
5-2. 핵심 정리
- RestTemplate: Spring 6 이후 비권장, 레거시 전용
- WebClient: Reactive/비동기가 필요한 대규모 환경 최적
- RestClient: Spring 6.1+ MVC 환경의 표준 선택 ⭐
6.참고
- https://docs.spring.io/spring-framework/reference/integration/rest-clients.html
- https://spring.io/blog/2023/07/13/new-in-spring-6-1-restclient
- https://velog.io/@sinryuji/Spring%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%A0-HTTP-Client%EB%A5%BC-%EA%B3%A8%EB%9D%BC%EB%B3%B4%EC%9E%90RestTemplate-vs-RestClient-vs-WebClient