[Spring Boot] 외부 API를 호출할 때 사용하는 HTTP Client

Euiyeon Park·2025년 7월 17일
0

Spring / SpringBoot

목록 보기
4/4
post-thumbnail

외부 API와 HttpClient

각종 프로젝트에서 서비스를 개발하다보면 외부 API를 호출해야하는 일이
심심치 않게 발생하는데, 이렇게 Spring Boot에서 외부 API를 호출할 때 사용하는
다양한 Http Client에 대해 알아보자!

HTTP Client란?

  • HTTP Client는 다른 서버(보통 HTTP 서버)로 HTTP 요청을 보내고,
    응답을 받아오는
    프로그램 또는 라이브러리를 의미한다.
  • 다시 말해 Java나 Spring 진영에서 클라이언트 역할을 하는게 Http Client다.

HTTP Client의 작업

역할설명
요청 구성(method, header, body)GET, POST, PUT 같은 메서드, 요청 헤더, 요청 본문 지정
요청 전송네트워크를 통해 외부 서버로 전송
응답 수신응답 코드(200, 404 등)와 본문(body) 등을 수신
응답 파싱JSON, XML을 Java 객체로 변환 가능

🌼1. RestTemplate(Deprecated 예정)

  • 동기적 요청 처리
  • Spring에서 오래된 기본 Http Client
  • 사용법이 간단하지만 deprecated 예정 - WebClient로 대체되는 추세
@RestController
public class ApiController {

    private final RestTemplate restTemplate = new RestTemplate();

    @GetMapping("/call-api")
    public String callApi() {
        String url = "https://api.example.com/data";
        // 해당 url로 GET 요청
        ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
        return response.getBody();
    }
}

🌼2. WebClient

  • 비동기(Reactive)& 논블로킹 지원 - Mono, Flux
  • 동기 방식으로도 사용 가능 - .block()
  • Spring이 권장하는 최신 방식

비동기 방식

@RestController
public class ApiController {

    private final WebClient webClient = WebClient.create();

    @GetMapping("/call-api")
    public Mono<String> callApi() {
        return webClient.get()				// GET 요청
                .uri("https://api.example.com/data")
                .retrieve()					// 응답 처리
                .bodyToMono(String.class);	// Mono로 래핑된 결과
    }
}

동기 방식

@GetMapping("/call-api-blocking")
public String callApiBlocking() {
    return webClient.get()
            .uri("https://api.example.com/data")
            .retrieve()
            .bodyToMono(String.class)
            .block(); // 동기 방식
}

Mono가 모에요?

  • Mono는 Reactor(비동기, 논블로킹 라이브러리)에서 제공하는 비동기 데이터 처리용 객체
  • 0개 또는 1개의 데이터를 비동기적으로 반환

🌼3. HttpClient

  • 동기 방식
  • Apache HttpComponents, CloseableHttpClient
  • Apache의 라이브러리 (spring-core에는 포함되지 않음❌) - 외부 의존성 필요
  • 커넥션 풀, 타임아웃 등 세밀한 설정이 가능
  • RestTemplate이나 WebClient의 하위 엔진으로도 사용됨
@RestController
public class ApiController {

    @GetMapping("/call-api-apache")
    public String callApiApache() throws IOException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet request = new HttpGet("https://api.example.com/data");
        CloseableHttpResponse response = client.execute(request);
        return EntityUtils.toString(response.getEntity());
    }
}

🌼4. OkHttp

  • 비동기 방식, 동기 방식 모두 지원
  • Square사에서 만든 경량 HTTP client - 외부 라이브러리 필요
  • 안드로이드나 네이티브 자바에서 많이 사용
  • 간결하고 빠름
@RestController
public class ApiController {

    private final OkHttpClient client = new OkHttpClient();

    @GetMapping("/call-api-okhttp")
    public String callApiOkHttp() throws IOException {
        Request request = new Request.Builder()
                .url("https://api.example.com/data")
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
}

🌼5. RestClient

  • 동기 방식
  • RestTemplate의 진화 버전
  • Java 17 이상의 HttpClient 기반
  • 타입 세이프한 요청 방식, 간결한 코드
  • Spring Boot 3.2 이상에서 정식 지원
@RestController
public class ApiController {

    private final RestClient restClient = RestClient.create();

    @GetMapping("/call-api-restclient")
    public String callApiRestClient() {
        return restClient.get()
                .uri("https://api.example.com/data")
                .retrieve()
                .body(String.class);
    }
}

🍀 Http Client의 동기/비동기 방식

동기 방식(RestTemplate, WebClient.block())

  • 요청을 보낸 스레드는 응답이 올 때까지 대기
  • 응답이 온 뒤에 다음 코드 를 실행
  • 요청/응답이 순차적이고 직관적이지만, 많은 요청 처리 시 스레드 낭비 우려
String body = restTemplate.getForObject(url, String.class)
// ❗ 응답이 올 때까지 기다림(동기 방식)
// ❗ 이 다음 코드는 응답을 받은 후에 실행됨

비동기 방식(WebClient, Mono, OkHttp async, CompletableFuture)

  • 요청을 보낸 후 스레드는 바로 다음 코드로 넘어가 실행
  • 응답은 나중에 도착하고, 콜백이나 리액티브 방식으로 처리됨
  • 응답이 나중에 오더라도 처리할 준비만 해두고,
    그동안 CPU는 다른 일을 처리할 수 있어 효율적
WebClient.create()
    .get()
    .uri(url)
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(body -> System.out.println("응답: " + body));
// ❗ 응답 기다리지 않고 바로 다음 코드 실행됨

🍀 Http Client별 동기/비동기 방식 정리

Http Client기본 동작 방식비동기 지원 여부비고
RestTemplate동기❌ 지원 안함Deprecated 예정
WebClient비동기(Mono/Flux 기반)✅ block()으로 동기도 가능Spring 5+ 추천
HttpClient동기⚠️ async 버전은 따로 있음설정 유연
OkHttp동기.enqueue()로 비동기 가능경량 & 빠름
RestClient동기❌ 아직은 비동기 지원 제한Spring 6+ 추천

동기/비동기 방식에서 고민점

사용자가 서비스를 이용하는 UX적인 관점에서 비동기 방식으로 요청을 처리하는게 뭐가 있을까?

profile
"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers

0개의 댓글