Using Spring WebClient Instead of RestTemplate: Advantages and Code Examples
This article explains why RestTemplate is deprecated in Spring 5+, introduces the reactive WebClient as its replacement, outlines its advantages such as non‑blocking I/O and functional style, and provides detailed code examples for creating a client, performing synchronous and asynchronous requests, handling errors, and configuring timeouts.
In Spring Framework 5+ RestTemplate is deprecated and WebClient is recommended for new projects.
WebClient offers non‑blocking I/O built on Reactor, a functional programming style, better streaming support, and improved error handling.
Creating a WebClient example:
import io.netty.channel.ChannelOption;
import io.netty.channel.ConnectTimeoutException;
import io.netty.handler.timeout.ReadTimeoutException;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.TimeoutException;
import jakarta.annotation.PostConstruct;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout)
.responseTimeout(Duration.ofMillis(requestTimeout))
.doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(readTimeout)));
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();Synchronous request (similar to RestTemplate) :
public String postSynchronously(String url, String requestBody) {
LOG.info("Going to hit API - URL {} Body {}", url, requestBody);
String response = "";
try {
response = client.method(HttpMethod.POST)
.uri(url)
.accept(MediaType.ALL)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class)
.block();
} catch (Exception ex) {
LOG.error("Error while calling API ", ex);
throw new RuntimeException("XYZ service api error: " + ex.getMessage());
} finally {
LOG.info("API Response {}", response);
}
return response;
}Asynchronous request using Mono:
public static Mono<String> makePostRequestAsync(String url, String postData) {
WebClient webClient = WebClient.builder().build();
return webClient.post()
.uri(url)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(BodyInserters.fromFormData("data", postData))
.retrieve()
.bodyToMono(String.class);
}Errors can be handled with onStatus for 4xx/5xx responses and by inspecting exceptions in subscribe callbacks.
Timeouts can be set per request with .timeout(Duration.ofMillis(readTimeout)), while connection timeout is configured once when building the client.
Conclusion: migrating to WebClient provides non‑blocking performance, richer error handling, and streaming capabilities, and it can still be used in a blocking style when needed.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.
