The RestTemplate provides a high-level API over HTTP client libraries in the form of a classic Spring Template class. It exposes the following groups of overloaded methods:

Initialization

RestTemplate uses the same HTTP library abstraction as RestClient. By default, it uses the SimpleClientHttpRequestFactory, but this can be changed via the constructor. See Client Request Factories.

Body

Objects passed into and returned from RestTemplate methods are converted to and from HTTP messages with the help of an HttpMessageConverter, see HTTP Message Conversion.

Migrating to RestClient

Applications can adopt RestClient in a gradual fashion, first focusing on API usage and then on infrastructure setup. You can consider the following steps:

  1. Create one or more RestClient from existing RestTemplate instances, like: RestClient restClient = RestClient.create(restTemplate). Gradually replace RestTemplate usage in your application, component by component, by focusing first on issuing requests. See the table below for API equivalents.

  2. Once all client requests go through RestClient instances, you can now work on replicating your existing RestTemplate instance creations by using RestClient.Builder. Because RestTemplate and RestClient share the same infrastructure, you can reuse custom ClientHttpRequestFactory or ClientHttpRequestInterceptor in your setup. See the RestClient builder API.

If no other library is available on the classpath, RestClient will choose the JdkClientHttpRequestFactory powered by the modern JDK HttpClient, whereas RestTemplate would pick the SimpleClientHttpRequestFactory that uses HttpURLConnection. This can explain subtle behavior difference at runtime at the HTTP level.

The following table shows RestClient equivalents for RestTemplate methods.

Table 2. RestClient equivalents for RestTemplate methods
RestTemplate method RestClient equivalent

getForObject(String, Class, Object…​)

get() .uri(String, Object…​) .retrieve() .body(Class)

getForObject(String, Class, Map)

get() .uri(String, Map) .retrieve() .body(Class)

getForObject(URI, Class)

get() .uri(URI) .retrieve() .body(Class)

getForEntity(String, Class, Object…​)

get() .uri(String, Object…​) .retrieve() .toEntity(Class)

getForEntity(String, Class, Map)

get() .uri(String, Map) .retrieve() .toEntity(Class)

getForEntity(URI, Class)

get() .uri(URI) .retrieve() .toEntity(Class)

headForHeaders(String, Object…​)

head() .uri(String, Object…​) .retrieve() .toBodilessEntity() .getHeaders()

headForHeaders(String, Map)

head() .uri(String, Map) .retrieve() .toBodilessEntity() .getHeaders()

headForHeaders(URI)

head() .uri(URI) .retrieve() .toBodilessEntity() .getHeaders()

postForLocation(String, Object, Object…​)

post() .uri(String, Object…​) .body(Object).retrieve() .toBodilessEntity() .getLocation()

postForLocation(String, Object, Map)

post() .uri(String, Map) .body(Object) .retrieve() .toBodilessEntity() .getLocation()

postForLocation(URI, Object)

post() .uri(URI) .body(Object) .retrieve() .toBodilessEntity() .getLocation()

postForObject(String, Object, Class, Object…​)

post() .uri(String, Object…​) .body(Object) .retrieve() .body(Class)

postForObject(String, Object, Class, Map)

post() .uri(String, Map) .body(Object) .retrieve() .body(Class)

postForObject(URI, Object, Class)

post() .uri(URI) .body(Object) .retrieve() .body(Class)

postForEntity(String, Object, Class, Object…​)

post() .uri(String, Object…​) .body(Object) .retrieve() .toEntity(Class)

postForEntity(String, Object, Class, Map)

post() .uri(String, Map) .body(Object) .retrieve() .toEntity(Class)

postForEntity(URI, Object, Class)

post() .uri(URI) .body(Object) .retrieve() .toEntity(Class)

put(String, Object, Object…​)

put() .uri(String, Object…​) .body(Object) .retrieve() .toBodilessEntity()

put(String, Object, Map)

put() .uri(String, Map) .body(Object) .retrieve() .toBodilessEntity()

put(URI, Object)

put() .uri(URI) .body(Object) .retrieve() .toBodilessEntity()

patchForObject(String, Object, Class, Object…​)

patch() .uri(String, Object…​) .body(Object) .retrieve() .body(Class)

patchForObject(String, Object, Class, Map)

patch() .uri(String, Map) .body(Object) .retrieve() .body(Class)

patchForObject(URI, Object, Class)

patch() .uri(URI) .body(Object) .retrieve() .body(Class)

delete(String, Object…​)

delete() .uri(String, Object…​) .retrieve() .toBodilessEntity()

delete(String, Map)

delete() .uri(String, Map) .retrieve() .toBodilessEntity()

delete(URI)

delete() .uri(URI) .retrieve() .toBodilessEntity()

optionsForAllow(String, Object…​)

options() .uri(String, Object…​) .retrieve() .toBodilessEntity() .getAllow()

optionsForAllow(String, Map)

options() .uri(String, Map) .retrieve() .toBodilessEntity() .getAllow()

optionsForAllow(URI)

options() .uri(URI) .retrieve() .toBodilessEntity() .getAllow()

exchange(String, HttpMethod, HttpEntity, Class, Object…​)

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(String, HttpMethod, HttpEntity, Class, Map)

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(URI, HttpMethod, HttpEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [1]

exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Object…​)

method(HttpMethod) .uri(String, Object…​) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Map)

method(HttpMethod) .uri(String, Map) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(URI, HttpMethod, HttpEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [1]

exchange(RequestEntity, Class)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(Class) [2]

exchange(RequestEntity, ParameterizedTypeReference)

method(HttpMethod) .uri(URI) .headers(Consumer<HttpHeaders>) .body(Object) .retrieve() .toEntity(ParameterizedTypeReference) [2]

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Object…​)

method(HttpMethod) .uri(String, Object…​) .exchange(ExchangeFunction)

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Map)

method(HttpMethod) .uri(String, Map) .exchange(ExchangeFunction)

execute(URI, HttpMethod, RequestCallback, ResponseExtractor)

method(HttpMethod) .uri(URI) .exchange(ExchangeFunction)

RestClient and RestTemplate instances share the same behavior when it comes to throwing exceptions (with the RestClientException type being at the top of the hierarchy). When RestTemplate consistently throws HttpClientErrorException for "4xx" response statues, RestClient allows for more flexibility with custom "status handlers".