이번에 프로젝트에서 맡게된 OAuth를 진행하다가 찾아보게된 RestTemplate vs WebClient vs RestClient!
RestTemplate, WebClient, RestClient 모두 HTTP 클라이언트 역할 을 한다. 세 라이브러리 모두 Spring 어플리케이션에서 HTTP 요청을 보내고 응답을 처리하는 데 사용된다
그래서 OAuth와 HTTP 요청의 관계가 무엇이냐?!
1. 인증요청: OAuth 프로세스는 클라이언트가 인증 서버에 HTTP GET 또는 POST 요청을 보내는 것으로 시작한다
2. 토큰 교환: 인증 코드를 액세스 토큰으로 교환할 때 HTTP POST 요청이 사용된다
3. API 호출: 액세스 토큰을 사용하여 보호된 리소스에 접근할 때, HTTP 요청의 헤더나 쿼리 파라미터에 토근을 포함시킨다
그럼 이제 정리 시작~ ✨
RestTemplate은Spring Framework에서 제공하는HTTP통신을 위한 템플릿으로,RESTful웹 서비스를 호출하는데 사용하는 클래스이다
특징
🔹Spring 3.0 부터 지원되는 HTTP 통신 템플릿이다
🔹 RESTful원칙을 준수하여 HTTP 메서드(GET, POST, PUT, DELETE 등)에 적합한 메서드를 제공한다
🔹JSON, XML, String 등 다양한 형식의 응답을 처리할 수 있다
🔹HttpClient를 추상화하여 사용자가 쉽게 REST API를 호출할 수 있도록 한다
장점
🔹 사용하기 간편하고, 복잡한 설정 없이 RESTful 서비스를 호출할 수 있다
🔹 RestTemplate은 동기적인 HTTP 호출을 수행하므로 호출 결과를 바로 반환받아 처리할 수 있다
🔹 JSON, XML 등 다양한 데이터 포맷을 지원한다
단점
🔹 동기식, 블로킹 방식으로 동작하여 고성능이 요구되는 환경에서는 제한적일 수 있다
🔹 비동기 및 리액티브 프로그래밍 지원이 부족하다
🔹 Spring 5 이후로 유지보수 모드로 전환되어 더 이상의 주요 업데이트가 없다
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
public class RestTemplateExample {
public void simpleGetRequest() {
RestTemplate restTemplate = new RestTemplate();
// 1. 단순 GET 요청
String url = "https://api.example.com/users/1";
String response = restTemplate.getForObject(url, String.class);
System.out.println("Response: " + response);
// 2. 응답 엔티티와 함께 GET 요청
ResponseEntity<User> responseEntity = restTemplate.getForEntity(url, User.class);
User user = responseEntity.getBody();
System.out.println("Status Code: " + responseEntity.getStatusCode());
// 3. 헤더를 포함한 요청
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer token123");
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<User> userResponse = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
User.class);
}
public void postRequest() {
RestTemplate restTemplate = new RestTemplate();
String url = "https://api.example.com/users";
// POST 요청
User newUser = new User("John", "Doe");
User createdUser = restTemplate.postForObject(url, newUser, User.class);
}
}
✅ GET, POST 등의 메서드를 직관적으로 호출
✅ 다양한 메서드 옵션(getForObject, getForEntity 등)
✅ 동기적 블로킹 방식으로 응답을 즉시 반환
Spring 5에서 도입된 비동기적이고 반응형인 HTTP 클라이언트이다
특징
🔹 비동기 및 논블로킹: Spring WebFlux의 반응형 프로그래밍 모델을 기반으로 구축되어있다
🔹 함수형 프로그래밍 스타일: 유창하고 표현력 있는 API를 제공하여 HTTP 요청을 구성하고 응답을 처리할 수 있다
장점
🔹 Mono, Flux를 활용한 Reactive 프로그래밍이 가능하다
🔹 Spring Security와 연동하여 인증 처리가 가능하다
🔹 유창하고 함수형 스타일의 많은 API를 제공한다
🔹 스트리밍을 지원해 대용량 데이터를 효율적으로 처리할 수 있다
단점
🔹Mono와 Flux 개념을 이해해야한다
🔹 비동기 및 반응형 코드의 특성상 디버깅이 더 복잡할 수 있다
🔹 web-flux 의존성을 주입해야하는 번거로움이 있다
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientExample {
public void simpleGetRequest() {
WebClient webClient = WebClient.create("https://api.example.com");
// 1. 단순 GET 요청
Mono<User> userMono = webClient.get()
.uri("/users/{id}", 1)
.retrieve()
.bodyToMono(User.class);
// 구독하여 결과 처리
userMono.subscribe(user ->
System.out.println("User name: " + user.getName())
);
// 2. 헤더를 포함한 요청
Mono<User> userWithAuthMono = webClient.get()
.uri("/users/{id}", 1)
.header("Authorization", "Bearer token123")
.retrieve()
.bodyToMono(User.class);
}
public void postRequest() {
WebClient webClient = WebClient.create("https://api.example.com");
// POST 요청
User newUser = new User("John", "Doe");
Mono<User> createdUserMono = webClient.post()
.uri("/users")
.bodyValue(newUser)
.retrieve()
.bodyToMono(User.class);
}
public void handleErrors() {
WebClient webClient = WebClient.create("https://api.example.com");
Mono<User> userMono = webClient.get()
.uri("/users/{id}", 999) // 존재하지 않는 사용자
.retrieve()
.onStatus(status -> status.is4xxClientError(),
response -> Mono.error(new RuntimeException("API not found")))
.bodyToMono(User.class);
}
}
✅ 체이닝 빙식의 API 제공
✅ Mono와 Flux를 통한 비동기 식 리액티브 프로그래밍
✅ subscribe() 메서드를 통해 결과 처리
✅ 오류 처리를 위한 onStatus 메서드 제공
Spring Framework 6.1에서 도입된 새로운 동기식
HTTP클라이언트이다
특징
🔹 현대적이고 유창한(fluent) API를 제공한다
🔹 동기식 블로킹 방식을 기본으로 하되, 필요시 비동기 호출도 지원한다
🔹 RestTemplate의 인프라를 기반으로 한 추상화 계층을 제공한다
🔹 HTTP 라이브러리에 대한 추상화를 제공한다
🔹 Java 객체를 HTTP 요청으로, HTTP 응답을 Java 객체로 변환하는 편리한 기능을 제공한다
장점
🔹 유창한 API를 통해 코드 가독성과 작성 용이성을 향상시킨다
🔹 기본 URI, 경로 변수, 요청 헤더 등을 쉽게 작성할 수 있다
🔹 Spring Framework의 다른 기능들과 잘 통합된다
단점
🔹비교적 최신 기술로 커뮤니티 지원과 예제가 아직 충분하지 않다
🔹Spring 6.1 이상의 최신 버전에서만 사용 가능하다
🔹WebClient의 완전한 리액티브 기능에 비해 제한적인 비동기를 지원한다
import org.springframework.web.client.RestClient;
public class RestClientExample {
public void simpleGetRequest() {
RestClient restClient = RestClient.create("https://api.example.com");
// 1. 단순 GET 요청
User user = restClient.get()
.uri("/users/{id}", 1)
.retrieve()
.body(User.class);
// 2. 헤더를 포함한 요청
User userWithAuth = restClient.get()
.uri("/users/{id}", 1)
.header("Authorization", "Bearer token123")
.retrieve()
.body(User.class);
}
public void postRequest() {
RestClient restClient = RestClient.create("https://api.example.com");
// POST 요청
User newUser = new User("John", "Doe");
User createdUser = restClient.post()
.uri("/users")
.body(newUser)
.retrieve()
.body(User.class);
}
public void handleErrors() {
RestClient restClient = RestClient.create("https://api.example.com");
try {
User user = restClient.get()
.uri("/users/{id}", 999) // 존재하지 않는 사용자
.retrieve()
.onStatus(status -> status.is4xxClientError(),
(request, response) -> {
throw new RuntimeException("API not found");
})
.body(User.class);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
// 비동기 요청 예제
public void asyncRequest() {
RestClient restClient = RestClient.create("https://api.example.com");
// CompletableFuture를 사용한 비동기 요청
CompletableFuture<User> futureUser = restClient.get()
.uri("/users/{id}", 1)
.retrieve()
.toEntity(User.class)
.thenApply(responseEntity -> responseEntity.getBody());
// 비동기 요청 결과 처리
futureUser.thenAccept(user ->
System.out.println("User name: " + user.getName())
);
}
}
✅ RestTemplate과 WebClient의 장점을 결합한 현대적 API
✅ 함수형 스타일의 체이닝 방식 제공
✅ 동기식 호출을 기본으로 하면서도 CompletableFuture를 통한 비동기 호출 지원
✅ 오류 처리를 위한 onStatus 메서드 제공