Mastering Spring 6 REST Calls: WebClient, RestTemplate, HTTP Interface & RestClient
Spring 6 offers four powerful ways to perform remote HTTP calls—WebClient, RestTemplate, HTTP Interface, and RestClient—each with distinct APIs, configuration options, and usage patterns, and this guide walks through their setup, method signatures, request handling, and error management for Java developers.
Environment: Spring 6.1.1 + JDK 17.
1. Introduction
Spring 6 provides four main ways to call remote HTTP services: WebClient, RestTemplate, HTTP Interface, and RestClient.
WebClient
WebClient, introduced in Spring 5, is a reactive, non‑blocking HTTP client offering better performance and lower memory usage than RestTemplate.
RestTemplate
RestTemplate, introduced in Spring 3, offers a simple, synchronous API for remote calls and remains widely used, though it is now in maintenance mode.
HTTP Interface
The HTTP Interface lets you define a Java interface annotated with HTTP exchange metadata; Spring generates a proxy that handles the underlying HTTP communication.
RestClient
RestClient, added in Spring 6.1.1, is a synchronous client with a modern, fluent API that abstracts the underlying HTTP library.
2. Remote Call Details
RestTemplate usage
RestTemplate provides high‑level methods such as getForObject , getForEntity , postForObject , exchange , etc., to perform CRUD operations.
Example of initializing RestTemplate with Apache HttpComponents:
<code>RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());</code>URI templates can be used with String variables or a Map<String,String> :
<code>String result = restTemplate.getForObject("http://pack.com/users/{userId}", String.class, 666);</code>Headers can be set via exchange() with a RequestEntity :
<code>String uriTemplate = "http://pack.com/users/{userId}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
.header("x-api-token", "aabbcc")
.build();
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
String responseHeader = response.getHeaders().getFirst("x-version");
String body = response.getBody();</code>If a MappingJackson2HttpMessageConverter is on the classpath, responses can be directly mapped to objects:
<code>User user = restTemplate.getForObject("http://pack.com/users/{userId}", User.class, 666);</code>RestTemplate registers a set of default message converters; you can customize them as needed.
WebClient example
<code>Mono<Person> result = client.get()
.uri("/users/{id}", id).accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(User.class);</code>HTTP Interface example
<code>@HttpExchange(url = "/demos")
public interface DemoInterface {
@PostExchange("/format3/{id}")
Users queryUser(@PathVariable Long id);
}</code> <code>@Service
public class DemoService {
private final DemoInterface demoInterface;
public DemoService() {
WebClient client = WebClient.builder().baseUrl("http://localhost:8088/").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
this.demoInterface = factory.createClient(DemoInterface.class);
}
public Users queryUser(Long id) {
return this.demoInterface.queryUser(id);
}
}</code>RestClient example
<code>// Default creation
RestClient restClient = RestClient.create();
// Custom builder
RestClient restClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory())
.baseUrl("http://localhost:8088")
.defaultUriVariables(Map.of("id", "888"))
.defaultHeader("x-api-token", "aabbcc")
.requestInterceptor((request, body, execution) -> {
System.out.println("Interceptor");
return execution.execute(request, body);
})
.requestInitializer(request -> {
System.out.println("Initializer");
request.getHeaders().add("x-version", "1.0.0");
})
.build();</code> <code>Users users = customClient.get()
.uri("/demos/users/{id}")
.retrieve()
.body(Users.class);</code> <code>ResponseEntity<Void> response = restClient.post()
.uri("/demos/users")
.contentType(APPLICATION_JSON)
.body(user)
.retrieve()
.toBodilessEntity();</code>Error handling can be customized with onStatus callbacks.
<code>Users users = customClient.get()
.uri("/demos/users/{id}")
.retrieve()
.onStatus(HttpStatusCode::isError, (req, resp) -> {
throw new RuntimeException(resp.getStatusCode().toString() + " request error");
})
.body(Users.class);</code>Conclusion
Spring 6 equips developers with a rich set of tools—WebClient, RestTemplate, HTTP Interface, and RestClient—to perform remote HTTP calls efficiently, offering high performance, low memory footprint, and flexible customization.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.