각종 프로젝트에서 서비스를 개발하다보면 외부 API를 호출해야하는 일이
심심치 않게 발생하는데, 이렇게 Spring Boot에서 외부 API를 호출할 때 사용하는
다양한 Http Client
에 대해 알아보자!
HTTP Client
는 다른 서버(보통 HTTP 서버)로 HTTP 요청을 보내고,Http Client
다.역할 | 설명 |
---|---|
요청 구성(method, header, body) | GET, POST, PUT 같은 메서드, 요청 헤더, 요청 본문 지정 |
요청 전송 | 네트워크를 통해 외부 서버로 전송 |
응답 수신 | 응답 코드(200, 404 등)와 본문(body) 등을 수신 |
응답 파싱 | JSON, XML을 Java 객체로 변환 가능 |
Http Client
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();
}
}
.block()
@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
는 Reactor(비동기, 논블로킹 라이브러리)에서 제공하는 비동기 데이터 처리용 객체HttpComponents
, CloseableHttpClient
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());
}
}
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();
}
}
}
RestTemplate
의 진화 버전HttpClient
기반@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);
}
}
String body = restTemplate.getForObject(url, String.class)
// ❗ 응답이 올 때까지 기다림(동기 방식)
// ❗ 이 다음 코드는 응답을 받은 후에 실행됨
WebClient.create()
.get()
.uri(url)
.retrieve()
.bodyToMono(String.class)
.subscribe(body -> System.out.println("응답: " + body));
// ❗ 응답 기다리지 않고 바로 다음 코드 실행됨
Http Client | 기본 동작 방식 | 비동기 지원 여부 | 비고 |
---|---|---|---|
RestTemplate | 동기 | ❌ 지원 안함 | Deprecated 예정 |
WebClient | 비동기(Mono/Flux 기반) | ✅ block()으로 동기도 가능 | Spring 5+ 추천 |
HttpClient | 동기 | ⚠️ async 버전은 따로 있음 | 설정 유연 |
OkHttp | 동기 | ✅ .enqueue() 로 비동기 가능 | 경량 & 빠름 |
RestClient | 동기 | ❌ 아직은 비동기 지원 제한 | Spring 6+ 추천 |
사용자가 서비스를 이용하는 UX적인 관점에서 비동기 방식으로 요청을 처리하는게 뭐가 있을까?