val result = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(MediaType.APPLICATION_JSON)
.exchange { request, response -> (1)
if (response.getStatusCode().is4xxClientError()) { (2)
throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) (2)
} else {
val pet: Pet = convertResponse(response) (3)
See the supported HTTP message converters in the dedicated section.
To serialize only a subset of the object properties, you can specify a Jackson JSON View, as the following example shows:
MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);
ResponseEntity<Void> response = restClient.post() // or RestTemplate.postForEntity
.contentType(APPLICATION_JSON)
.body(value)
.retrieve()
.toBodilessEntity();
To send multipart data, you need to provide a MultiValueMap<String, Object> whose values may be an Object for part content, a Resource for a file part, or an HttpEntity for part content with headers.
For example:
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
// send using RestClient.post or RestTemplate.postForEntity
In most cases, you do not have to specify the Content-Type for each part.
The content type is determined automatically based on the HttpMessageConverter chosen to serialize it or, in the case of a Resource, based on the file extension.
If necessary, you can explicitly provide the MediaType with an HttpEntity wrapper.
Once the MultiValueMap is ready, you can use it as the body of a POST request, using RestClient.post().body(parts) (or RestTemplate.postForObject).
If the MultiValueMap contains at least one non-String value, the Content-Type is set to multipart/form-data by the FormHttpMessageConverter.
If the MultiValueMap has String values, the Content-Type defaults to application/x-www-form-urlencoded.
If necessary the Content-Type may also be set explicitly.
To execute the HTTP request, RestClient uses a client HTTP library.
These libraries are adapted via the ClientRequestFactory interface.
Various implementations are available:
If no request factory is specified when the RestClient was built, it will use the Apache or Jetty HttpClient if they are available on the classpath.
Otherwise, if the java.net.http module is loaded, it will use Java’s HttpClient.
Finally, it will resort to the simple default.
Note that the SimpleClientHttpRequestFactory may raise an exception when accessing the status of a response that represents an error (for example, 401).
If this is an issue, use any of the alternative request factories.
WebClient is a non-blocking, reactive client to perform HTTP requests. It was
introduced in 5.0 and offers an alternative to the RestTemplate, with support for
synchronous, asynchronous, and streaming scenarios.
WebClient supports the following:
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:
getForEntity
Retrieves a ResponseEntity (that is, status, headers, and body) by using GET.
headForHeaders
Retrieves all headers for a resource by using HEAD.
postForLocation
Creates a new resource by using POST and returns the Location header from the response.
postForObject
Creates a new resource by using POST and returns the representation from the response.
postForEntity
Creates a new resource by using POST and returns the representation from the response.
Creates or updates a resource by using PUT.
patchForObject
Updates a resource by using PATCH and returns the representation from the response.
Note that the JDK HttpURLConnection does not support PATCH, but Apache HttpComponents and others do.
delete
Deletes the resources at the specified URI by using DELETE.
optionsForAllow
Retrieves allowed HTTP methods for a resource by using ALLOW.
exchange
More generalized (and less opinionated) version of the preceding methods that provides extra flexibility when needed.
It accepts a RequestEntity (including HTTP method, URL, headers, and body as input) and returns a ResponseEntity.
These methods allow the use of ParameterizedTypeReference instead of Class to specify
a response type with generics.
execute
The most generalized way to perform a request, with full control over request
preparation and response extraction through callback interfaces.
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.
RestTemplate can be instrumented for observability, in order to produce metrics and traces.
See the RestTemplate Observability support section.
The following table shows RestClient equivalents for RestTemplate methods.
It can be used to migrate from the latter to the former.
Table 2. RestClient equivalents for RestTemplate methods
exchange(String, HttpMethod, HttpEntity, Class, Object…)
method(HttpMethod)
.uri(String, Object…)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(Class) ]
exchange(String, HttpMethod, HttpEntity, Class, Map)
method(HttpMethod)
.uri(String, Map)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(Class)
exchange(URI, HttpMethod, HttpEntity, Class)
method(HttpMethod)
.uri(URI)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(Class)
exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Object…)
method(HttpMethod)
.uri(String, Object…)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(ParameterizedTypeReference)
exchange(String, HttpMethod, HttpEntity, ParameterizedTypeReference, Map)
method(HttpMethod)
.uri(String, Map)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(ParameterizedTypeReference)
exchange(URI, HttpMethod, HttpEntity, ParameterizedTypeReference)
method(HttpMethod)
.uri(URI)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(ParameterizedTypeReference)
exchange(RequestEntity, Class)
method(HttpMethod)
.uri(URI)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(Class)
exchange(RequestEntity, ParameterizedTypeReference)
method(HttpMethod)
.uri(URI)
.headers(Consumer<HttpHeaders>)
.body(Object)
.retrieve()
.toEntity(ParameterizedTypeReference)
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)
The Spring Framework lets you define an HTTP service as a Java interface with
@HttpExchange methods. You can pass such an interface to HttpServiceProxyFactory
to create a proxy which performs requests through an HTTP client such as RestClient
or WebClient. You can also implement the interface from an @Controller for server
request handling.
Start by creating the interface with @HttpExchange methods:
interface RepositoryService {
@GetExchange("/repos/{owner}/{repo}")
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
// more HTTP exchange methods...
Now you can create a proxy that performs requests when methods are called.
For RestClient:
RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
For WebClient:
WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
For RestTemplate:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
@HttpExchange is supported at the type level where it applies to all methods:
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
interface RepositoryService {
@GetExchange
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
void updateRepository(@PathVariable String owner, @PathVariable String repo,
@RequestParam String name, @RequestParam String description, @RequestParam String homepage);
Annotated, HTTP exchange methods support flexible method signatures with the following
method parameters:
UriBuilderFactory
Provide a UriBuilderFactory to expand the URI template and URI variables with.
In effect, replaces the UriBuilderFactory (and its base URL) of the underlying client.
HttpMethod
Dynamically set the HTTP method for the request, overriding the annotation’s method attribute
@RequestHeader
Add a request header or multiple headers. The argument may be a Map<String, ?> or
MultiValueMap<String, ?> with multiple headers, a Collection<?> of values, or an
individual value. Type conversion is supported for non-String values. This overrides
the annotation’s headers attribute.
@PathVariable
Add a variable for expand a placeholder in the request URL. The argument may be a
Map<String, ?> with multiple variables, or an individual value. Type conversion
is supported for non-String values.
@RequestAttribute
Provide an Object to add as a request attribute. Only supported by RestClient
and WebClient.
@RequestBody
Provide the body of the request either as an Object to be serialized, or a
Reactive Streams Publisher such as Mono, Flux, or any other async type supported
through the configured ReactiveAdapterRegistry.
@RequestParam
Add a request parameter or multiple parameters. The argument may be a Map<String, ?>
or MultiValueMap<String, ?> with multiple parameters, a Collection<?> of values, or
an individual value. Type conversion is supported for non-String values.
When "content-type" is set to "application/x-www-form-urlencoded", request
parameters are encoded in the request body. Otherwise, they are added as URL query
parameters.
@RequestPart
Add a request part, which may be a String (form field), Resource (file part),
Object (entity to be encoded, for example, as JSON), HttpEntity (part content and headers),
a Spring Part, or Reactive Streams Publisher of any of the above.
MultipartFile
Add a request part from a MultipartFile, typically used in a Spring MVC controller
where it represents an uploaded file.
@CookieValue
Add a cookie or multiple cookies. The argument may be a Map<String, ?> or
MultiValueMap<String, ?> with multiple cookies, a Collection<?> of values, or an
individual value. Type conversion is supported for non-String values.
Method parameters cannot be null unless the required attribute (where available on a
parameter annotation) is set to false, or the parameter is marked optional as determined by
MethodParameter#isOptional.
The supported return values depend on the underlying client.
Clients adapted to HttpExchangeAdapter such as RestClient and RestTemplate
support synchronous return values:
ResponseEntity<Void>
Perform the given request and return a ResponseEntity with the status and headers.
ResponseEntity<T>
Perform the given request, decode the response content to the declared return type, and
return a ResponseEntity with the status, headers, and the decoded body.
Clients adapted to ReactorHttpExchangeAdapter such as WebClient, support all of above
as well as reactive variants. The table below shows Reactor types, but you can also use
other reactive types that are supported through the ReactiveAdapterRegistry:
Mono<HttpHeaders>
Perform the given request, release the response content, if any, and return the
response headers.
Mono<T>
Perform the given request and decode the response content to the declared return type.
Flux<T>
Perform the given request and decode the response content to a stream of the declared
element type.
Mono<ResponseEntity<Void>>
Perform the given request, and release the response content, if any, and return a
ResponseEntity with the status and headers.
Mono<ResponseEntity<T>>
Perform the given request, decode the response content to the declared return type, and
return a ResponseEntity with the status, headers, and the decoded body.
Mono<ResponseEntity<Flux<T>>
Perform the given request, decode the response content to a stream of the declared
element type, and return a ResponseEntity with the status, headers, and the decoded
response body stream.
By default, the timeout for synchronous return values with ReactorHttpExchangeAdapter
depends on how the underlying HTTP client is configured. You can set a blockTimeout
value on the adapter level as well, but we recommend relying on timeout settings of the
underlying HTTP client, which operates at a lower level and provides more control.
To customize error response handling, you need to configure the underlying HTTP client.
For RestClient:
By default, RestClient raises RestClientException for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
RestClient restClient = RestClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
.build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
For more details and options, such as suppressing error status codes, see the Javadoc of
defaultStatusHandler in RestClient.Builder.
For WebClient:
By default, WebClient raises WebClientResponseException for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
WebClient webClient = WebClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
.build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();
For more details and options, such as suppressing error status codes, see the Javadoc of
defaultStatusHandler in WebClient.Builder.
For RestTemplate:
By default, RestTemplate raises RestClientException for 4xx and 5xx HTTP status codes.
To customize this, register an error handler that applies to all responses
performed through the client:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
For more details and options, see the Javadoc of setErrorHandler in RestTemplate and
the ResponseErrorHandler hierarchy.
1. HttpEntity headers and body have to be supplied to the RestClient via headers(Consumer<HttpHeaders>) and body(Object).
2. RequestEntity method, URI, headers and body have to be supplied to the RestClient via method(HttpMethod), uri(URI), headers(Consumer<HttpHeaders>) and body(Object).
Integration
JMS (Java Message Service)
Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra™, and Apache Geode™ are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java™, Java™ SE, Java™ EE, and OpenJDK™ are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners.