From 7b5effecf30598a8f15831819bd357862fb2dd4f Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 31 Aug 2023 12:40:06 +0200 Subject: [PATCH] Reference documentation for `RestClient` In addition to providing reference documentation for the `RestClient`, this commit also shortens the `RestTemplate` section. Closes gh-30826 --- .../ROOT/pages/integration/rest-clients.adoc | 714 +++++++++++------- 1 file changed, 456 insertions(+), 258 deletions(-) diff --git a/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc b/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc index e1a031e33c3..d186d73b087 100644 --- a/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc +++ b/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc @@ -12,353 +12,551 @@ The Spring Framework provides the following choices for making calls to REST end [[rest-restclient]] == `RestClient` -Reference documentation is forthcoming. -For now, please refer to the https://docs.spring.io/spring-framework/docs/6.1.0-M2/javadoc-api/org/springframework/web/client/RestClient.html[API documentation]. +The `RestClient` is a synchronous HTTP client that offers a modern, fluent API. +It offers an abstraction over HTTP libraries that allows for convenient conversion from Java object to HTTP request, and creation of objects from the HTTP response. +=== Creating a `RestClient` -[[rest-webclient]] -== `WebClient` - -`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: - -* Non-blocking I/O. -* Reactive Streams back pressure. -* High concurrency with fewer hardware resources. -* Functional-style, fluent API that takes advantage of Java 8 lambdas. -* Synchronous and asynchronous interactions. -* Streaming up to or streaming down from a server. +The `RestClient` is created using one of the static `create` methods. +You can also use `builder` to get a builder with further options, such as specifying which HTTP library to use (see <>) and which message converters to use (see <>), setting a default URI, default path variables, a default request headers, or `uriBuilderFactory`, or registering interceptors and initializers. -See xref:web/webflux-webclient.adoc[WebClient] for more details. +Once created (or built), the `RestClient` can be used safely by multiple threads. +The following sample shows how to create a default `RestClient`, and how to build a custom one. +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim",role="primary"] +---- +RestClient defaultClient = RestClient.create(); +RestClient customClient = RestClient.builder() + .requestFactory(new HttpComponentsClientHttpRequestFactory()) + .messageConverters(converters -> converters.add(new MyCustomMessageConverter())) + .baseUrl("https://example.com") + .defaultUriVariables(Map.of("variable", "foo")) + .defaultHeader("My-Header", "Foo") + .requestInterceptor(myCustomInterceptor) + .requestInitializer(myCustomInitializer) + .build(); +---- -[[rest-resttemplate]] -== `RestTemplate` +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim",role="secondary"] +---- +val defaultClient = RestClient.create() -The `RestTemplate` provides a higher level API over HTTP client libraries. It makes it -easy to invoke REST endpoints in a single line. It exposes the following groups of -overloaded methods: +val customClient = RestClient.builder() + .requestFactory(HttpComponentsClientHttpRequestFactory()) + .messageConverters(converters -> converters.add(MyCustomMessageConverter())) + .baseUrl("https://example.com") + .defaultUriVariables(Map.of("variable", "foo")) + .defaultHeader("My-Header", "Foo") + .requestInterceptor(myCustomInterceptor) + .requestInitializer(myCustomInitializer) + .build() +---- +====== -NOTE: The xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] offers a more modern API for synchronous HTTP access. -For asynchronous and streaming scenarios, consider the reactive xref:web/webflux-webclient.adoc[WebClient]. +=== Using the `RestClient` -[[rest-overview-of-resttemplate-methods-tbl]] -.RestTemplate methods -[cols="1,3"] -|=== -| Method group | Description +When making an HTTP request with the `RestClient`, the first thing to specify is which HTTP method to use. +This can be done with `method(HttpMethod)`, or with the convenience methods `get()`, `head()`, `post()`, and so on. -| `getForObject` -| Retrieves a representation via GET. +==== Request URL -| `getForEntity` -| Retrieves a `ResponseEntity` (that is, status, headers, and body) by using GET. +Next, the request URI can be specified with the `uri` methods +This step is optional, and can be skipped if the `RestClient` is configured with a default URI. +The URL is typically specified as `String`, with optional URI template variables. +String URLs are encoded by default, but this can be changed by building a client with a custom `uriBuilderFactory`. -| `headForHeaders` -| Retrieves all headers for a resource by using HEAD. +The URL can also be provided with a function, or as `java.net.URI`, both of which are not encoded. +For more details on working with and encoding URIs, see xref:web/webmvc/mvc-uri-building.adoc[URI Links]. -| `postForLocation` -| Creates a new resource by using POST and returns the `Location` header from the response. +==== Request headers and body -| `postForObject` -| Creates a new resource by using POST and returns the representation from the response. +If necessary, the HTTP request can be manipulated, by adding request headers with `header(String, String)`, `headers(Consumer`, or with the convenience methods `accept(MediaType...)`, `acceptCharset(Charset...)` and so on. +For HTTP request that can contain a body (`POST`, `PUT`, and `PATCH`), additional methods are available: `contentType(MediaType)`, and `contentLength(long)`. -| `postForEntity` -| Creates a new resource by using POST and returns the representation from the response. +The request body itself can be set by `body(Object)`, which internally uses <>. +Alternatively, the request body can be set using a `ParameterizedTypeReference`, allowing you to use generics. +Finally, the body can be set to a callback function that writes to an `OutputStream`. + +==== Retrieving the response +Once the request has been set up, the HTTP response is accessed by invoking `retrieve()`. +The response body can be accessed by using `body(Class)`, or `body(ParameterizedTypeReference)` for parameterized types like lists. +The `body` method converts the response contents into various types, for instance bytes can be converted into a `String`, JSON into objects using Jackson, and so on (see <>). -| `put` -| Creates or updates a resource by using PUT. +The response can also be converted into a `ResponseEntity`, giving access to the response headers as well as the body. + +This sample shows how `RestClient` can be used to perform a simple GET request. -| `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. +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim,quotes",role="primary"] +---- +String result = restClient.get() <1> + .uri("https://example.com") <2> + .retrieve() <3> + .body(String.class); <4> + +System.out.println(result); <5> +---- +<1> Set up a GET request +<2> Specify the URL to connect to +<3> Retrieve the response +<4> Convert the response into a string +<5> Print the result + +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +---- +val result= restClient.get() <1> + .uri("https://example.com") <2> + .retrieve() <3> + .body() <4> + +println(result) <5> +---- +<1> Set up a GET request +<2> Specify the URL to connect to +<3> Retrieve the response +<4> Convert the response into a string +<5> Print the result +====== + +Access to the response status code and headers is provided through `ResponseEntity`: + +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim,quotes",role="primary"] +---- +ResponseEntity result = restClient.get() <1> + .uri("https://example.com") <1> + .retrieve() + .toEntity(String.class); <2> + +System.out.println("Response status: " + result.getStatusCode()); <3> +System.out.println("Response headers: " + result.getHeaders()); <3> +System.out.println("Contents: " + result.getBody()); <3> +---- +<1> Set up a GET request for the specified URL +<2> Convert the response into a `ResponseEntity` +<3> Print the result + +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +---- +val result = restClient.get() <1> + .uri("https://example.com") <1> + .retrieve() + .toEntity() <2> + +println("Response status: " + result.statusCode) <3> +println("Response headers: " + result.headers) <3> +println("Contents: " + result.body) <3> +---- +<1> Set up a GET request for the specified URL +<2> Convert the response into a `ResponseEntity` +<3> Print the result +====== + +`RestClient` can convert JSON to objects, using the Jackson library. +Note the usage of uri variables in this sample, and that the `Accept` header is set to JSON. + +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim,quotes",role="primary"] +---- +int id = ...; +Pet pet = restClient.get() + .uri("https://petclinic.example.com/pets/{id}", id) <1> + .accept(APPLICATION_JSON) <2> + .retrieve() + .body(Pet.class); <3> +---- +<1> Using URI variables +<2> Set the `Accept` header to `application/json` +<3> Convert the JSON response into a `Pet` domain object + +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +---- +val id = ... +val pet = restClient.get() + .uri("https://petclinic.example.com/pets/{id}", id) <1> + .accept(APPLICATION_JSON) <2> + .retrieve() + .body() <3> +---- +<1> Using URI variables +<2> Set the `Accept` header to `application/json` +<3> Convert the JSON response into a `Pet` domain object +====== + +In the next sample, `RestClient` is used to perform a POST request that contains JSON, which again is converted using Jackson. + +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim,quotes",role="primary"] +---- +Pet pet = ... <1> +ResponseEntity response = restClient.post() <2> + .uri("https://petclinic.example.com/pets/new") <2> + .contentType(APPLICATION_JSON) <3> + .body(pet) <4> + .retrieve() + .toBodilessEntity(); <5> +---- +<1> Create a `Pet` domain object +<2> Set up a POST request, and the URL to connect to +<3> Set the `Content-Type` header to `application/json` +<4> Use `pet` as the request body +<5> Convert the response into a response entity with no body. + +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +---- +val pet: Pet = ... <1> +val response = restClient.post() <2> + .uri("https://petclinic.example.com/pets/new") <2> + .contentType(APPLICATION_JSON) <3> + .body(pet) <4> + .retrieve() + .toBodilessEntity() <5> +---- +<1> Create a `Pet` domain object +<2> Set up a POST request, and the URL to connect to +<3> Set the `Content-Type` header to `application/json` +<4> Use `pet` as the request body +<5> Convert the response into a response entity with no body. +====== + +==== Error handling +By default, `RestClient` throws a subclass of `RestClientException` when retrieving a response with a 4xx or 5xx status code. +This behavior can be overriden using `onStatus`. + +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim,quotes",role="primary"] +---- +String result = restClient.get() <1> + .uri("https://example.com/this-url-does-not-exist") <1> + .retrieve() + .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { <2> + throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) <3> + }) + .body(String.class); +---- +<1> Create a GET request for a URL that returns a 404 status code +<2> Set up a status handler for all 4xx status codes +<3> Throw a custom exception + +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +---- +val result = restClient.get() <1> + .uri("https://example.com/this-url-does-not-exist") <1> + .retrieve() + .onStatus(HttpStatusCode::is4xxClientError) { _, response -> <2> + throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) } <3> + .body() +---- +<1> Create a GET request for a URL that returns a 404 status code +<2> Set up a status handler for all 4xx status codes +<3> Throw a custom exception +====== + +==== Exchange +For more advanced scenarios, the `RestClient` gives access to the underlying HTTP request and response through the `exchange` method, which can be used instead of `retrieve()`. +Status handlers are not applied when you exchange, because the exchange function already provides access to the full response, allowing you to perform any error handling necessary. + +[tabs] +====== +Java:: ++ +[source,java,indent=0,subs="verbatim,quotes",role="primary"] +---- +Pet result = restClient.get() + .uri("https://petclinic.example.com/pets/{id}", id) + .accept(APPLICATION_JSON) + .exchange((request, response) -> { <1> + if (response.getStatusCode().is4xxClientError()) { <2> + throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); <2> + } + else { + Pet pet = convertResponse(response); <3> + return pet; + } + }); +---- +<1> `exchange` provides the request and response +<2> Throw an exception when the response has a 4xx status code +<3> Convert the response into a Pet domain object + +Kotlin:: ++ +[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] +---- +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> + pet + } + } +---- +<1> `exchange` provides the request and response +<2> Throw an exception when the response has a 4xx status code +<3> Convert the response into a Pet domain object +====== -| `delete` -| Deletes the resources at the specified URI by using DELETE. -| `optionsForAllow` -| Retrieves allowed HTTP methods for a resource by using ALLOW. +[[rest-message-conversion]] +=== HTTP Message Conversion +[.small]#xref:web/webflux/reactive-spring.adoc#webflux-codecs[See equivalent in the Reactive stack]# -| `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`. +The `spring-web` module contains the `HttpMessageConverter` interface for reading and writing the body of HTTP requests and responses through `InputStream` and `OutputStream`. +`HttpMessageConverter` instances are used on the client side (for example, in the `RestClient`) and on the server side (for example, in Spring MVC REST controllers). -These methods allow the use of `ParameterizedTypeReference` instead of `Class` to specify -a response type with generics. +Concrete implementations for the main media (MIME) types are provided in the framework and are, by default, registered with the `RestClient` and `RestTemplate` on the client side and with `RequestMappingHandlerAdapter` on the server side (see xref:web/webmvc/mvc-config/message-converters.adoc[Configuring Message Converters]). -| `execute` -| The most generalized way to perform a request, with full control over request -preparation and response extraction through callback interfaces. +Several implementations of `HttpMessageConverter` are described below. +Refer to the {api-spring-framework}/http/converter/HttpMessageConverter.html[`HttpMessageConverter` Javadoc] for the complete list. +For all converters, a default media type is used, but you can override it by setting the `supportedMediaTypes` property. +[[rest-message-converters-tbl]] +.HttpMessageConverter Implementations +[cols="1,3"] |=== +| MessageConverter | Description -[[rest-resttemplate-create]] -=== Initialization +| `StringHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write `String` instances from the HTTP request and response. +By default, this converter supports all text media types(`text/{asterisk}`) and writes with a `Content-Type` of `text/plain`. -The default constructor uses `java.net.HttpURLConnection` to perform requests. You can -switch to a different HTTP library with an implementation of `ClientHttpRequestFactory`. -There is built-in support for the following: +| `FormHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write form data from the HTTP request and response. +By default, this converter reads and writes the `application/x-www-form-urlencoded` media type. +Form data is read from and written into a `MultiValueMap`. +The converter can also write (but not read) multipart data read from a `MultiValueMap`. +By default, `multipart/form-data` is supported. +Additional multipart subtypes can be supported for writing form data. +Consult the javadoc for `FormHttpMessageConverter` for further details. -* Apache HttpComponents -* Netty -* OkHttp +| `ByteArrayHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write byte arrays from the HTTP request and response. +By default, this converter supports all media types (`{asterisk}/{asterisk}`) and writes with a `Content-Type` of `application/octet-stream`. +You can override this by setting the `supportedMediaTypes` property and overriding `getContentType(byte[])`. -For example, to switch to Apache HttpComponents, you can use the following: +| `MarshallingHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write XML by using Spring's `Marshaller` and `Unmarshaller` abstractions from the `org.springframework.oxm` package. +This converter requires a `Marshaller` and `Unmarshaller` before it can be used. +You can inject these through constructor or bean properties. +By default, this converter supports `text/xml` and `application/xml`. -[source,java,indent=0,subs="verbatim,quotes"] ----- - RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); ----- +| `MappingJackson2HttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write JSON by using Jackson's `ObjectMapper`. +You can customize JSON mapping as needed through the use of Jackson's provided annotations. +When you need further control (for cases where custom JSON serializers/deserializers need to be provided for specific types), you can inject a custom `ObjectMapper` through the `ObjectMapper` property. +By default, this converter supports `application/json`. -Each `ClientHttpRequestFactory` exposes configuration options specific to the underlying -HTTP client library -- for example, for credentials, connection pooling, and other details. +| `MappingJackson2XmlHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write XML by using https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's `XmlMapper`. +You can customize XML mapping as needed through the use of JAXB or Jackson's provided annotations. +When you need further control (for cases where custom XML serializers/deserializers need to be provided for specific types), you can inject a custom `XmlMapper` through the `ObjectMapper` property. +By default, this converter supports `application/xml`. -TIP: Note that the `java.net` implementation for HTTP requests can raise an exception when -accessing the status of a response that represents an error (such as 401). If this is an -issue, switch to another HTTP client library. +| `SourceHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write `javax.xml.transform.Source` from the HTTP request and response. +Only `DOMSource`, `SAXSource`, and `StreamSource` are supported. +By default, this converter supports `text/xml` and `application/xml`. -NOTE: `RestTemplate` can be instrumented for observability, in order to produce metrics and traces. -See the xref:integration/observability.adoc#http-client.resttemplate[RestTemplate Observability support] section. +|=== -[[rest-resttemplate-uri]] -==== URIs +By default, `RestClient` and `RestTemplate` register all built-in message converters, depending on the availability of underlying libraries on the classpath. +You can also set the message converters to use explicitly, by using `messageConverters` on the `RestClient` builder, or via the `messageConverters` property of `RestTemplate`. -Many of the `RestTemplate` methods accept a URI template and URI template variables, -either as a `String` variable argument, or as `Map`. +==== Jackson JSON Views -The following example uses a `String` variable argument: +To serialize only a subset of the object properties, you can specify a https://www.baeldung.com/jackson-json-view-annotation[Jackson JSON View], as the following example shows: -[source,java,indent=0,subs="verbatim,quotes"] ----- - String result = restTemplate.getForObject( - "https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21"); +[source,java,indent=0,subs="verbatim"] ---- +MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23")); +value.setSerializationView(User.WithoutPasswordView.class); -The following example uses a `Map`: +ResponseEntity response = restClient.post() // or RestTemplate.postForEntity + .contentType(APPLICATION_JSON) + .body(value) + .retrieve() + .toBodilessEntity(); -[source,java,indent=0,subs="verbatim,quotes"] ---- - Map vars = Collections.singletonMap("hotel", "42"); - String result = restTemplate.getForObject( - "https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); ----- +==== Multipart -Keep in mind URI templates are automatically encoded, as the following example shows: +To send multipart data, you need to provide a `MultiValueMap` 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: -[source,java,indent=0,subs="verbatim,quotes"] +[source,java,indent=0,subs="verbatim"] ---- - restTemplate.getForObject("https://example.com/hotel list", String.class); +MultiValueMap parts = new LinkedMultiValueMap<>(); - // Results in request to "https://example.com/hotel%20list" ----- +parts.add("fieldPart", "fieldValue"); +parts.add("filePart", new FileSystemResource("...logo.png")); +parts.add("jsonPart", new Person("Jason")); -You can use the `uriTemplateHandler` property of `RestTemplate` to customize how URIs -are encoded. Alternatively, you can prepare a `java.net.URI` and pass it into one of -the `RestTemplate` methods that accepts a `URI`. +HttpHeaders headers = new HttpHeaders(); +headers.setContentType(MediaType.APPLICATION_XML); +parts.add("xmlPart", new HttpEntity<>(myBean, headers)); -For more details on working with and encoding URIs, see xref:web/webmvc/mvc-uri-building.adoc[URI Links]. +// send using RestClient.post or RestTemplate.postForEntity +---- -[[rest-template-headers]] -==== Headers +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. -You can use the `exchange()` methods to specify request headers, as the following example shows: +Once the `MultiValueMap` is ready, you can use it as the body of a POST request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`). -[source,java,indent=0,subs="verbatim,quotes"] ----- - String uriTemplate = "https://example.com/hotels/{hotel}"; - URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42); - - RequestEntity requestEntity = RequestEntity.get(uri) - .header("MyRequestHeader", "MyValue") - .build(); +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. - ResponseEntity response = template.exchange(requestEntity, String.class); +[[rest-request-factories]] +=== Client Request Factories - String responseHeader = response.getHeaders().getFirst("MyResponseHeader"); - String body = response.getBody(); ----- +To execute the HTTP request, `RestClient` uses a client HTTP library. +These libraries are adapted via the `ClientRequestFactory` interface. +Various implementations are available: -You can obtain response headers through many `RestTemplate` method variants that return -`ResponseEntity`. +* `JdkClientHttpRequestFactory` for Java's `HttpClient`, +* `HttpComponentsClientHttpRequestFactory` for use with Apache HTTP Components `HttpClient`, +* `JettyClientHttpRequestFactory` for Jetty's `HttpClient`, +* `ReactorNettyClientRequestFactory` for Reactor Netty's `HttpClient`, +* `SimpleClientHttpRequestFactory` as a simple default. -[[rest-template-body]] -=== Body -Objects passed into and returned from `RestTemplate` methods are converted to and from raw -content with the help of an `HttpMessageConverter`. +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. -On a POST, an input object is serialized to the request body, as the following example shows: +[[rest-webclient]] +== `WebClient` ----- -URI location = template.postForLocation("https://example.com/people", person); ----- +`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. -You need not explicitly set the Content-Type header of the request. In most cases, -you can find a compatible message converter based on the source `Object` type, and the chosen -message converter sets the content type accordingly. If necessary, you can use the -`exchange` methods to explicitly provide the `Content-Type` request header, and that, in -turn, influences what message converter is selected. +`WebClient` supports the following: -On a GET, the body of the response is deserialized to an output `Object`, as the following example shows: +* Non-blocking I/O. +* Reactive Streams back pressure. +* High concurrency with fewer hardware resources. +* Functional-style, fluent API that takes advantage of Java 8 lambdas. +* Synchronous and asynchronous interactions. +* Streaming up to or streaming down from a server. ----- -Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42); ----- +See xref:web/webflux-webclient.adoc[WebClient] for more details. -The `Accept` header of the request does not need to be explicitly set. In most cases, -a compatible message converter can be found based on the expected response type, which -then helps to populate the `Accept` header. If necessary, you can use the `exchange` -methods to provide the `Accept` header explicitly. -By default, `RestTemplate` registers all built-in -xref:integration/rest-clients.adoc#rest-message-conversion[message converters], depending on classpath checks that help -to determine what optional conversion libraries are present. You can also set the message -converters to use explicitly. -[[rest-message-conversion]] -==== Message Conversion -[.small]#xref:web/webflux/reactive-spring.adoc#webflux-codecs[See equivalent in the Reactive stack]# -The `spring-web` module contains the `HttpMessageConverter` contract for reading and -writing the body of HTTP requests and responses through `InputStream` and `OutputStream`. -`HttpMessageConverter` instances are used on the client side (for example, in the `RestTemplate`) and -on the server side (for example, in Spring MVC REST controllers). +[[rest-resttemplate]] +== `RestTemplate` -Concrete implementations for the main media (MIME) types are provided in the framework -and are, by default, registered with the `RestTemplate` on the client side and with -`RequestMappingHandlerAdapter` on the server side (see -xref:web/webmvc/mvc-config/message-converters.adoc[Configuring Message Converters]). +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: -The implementations of `HttpMessageConverter` are described in the following sections. -For all converters, a default media type is used, but you can override it by setting the -`supportedMediaTypes` bean property. The following table describes each implementation: +NOTE: The xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] offers a more modern API for synchronous HTTP access. +For asynchronous and streaming scenarios, consider the reactive xref:web/webflux-webclient.adoc[WebClient]. -[[rest-message-converters-tbl]] -.HttpMessageConverter Implementations +[[rest-overview-of-resttemplate-methods-tbl]] +.RestTemplate methods [cols="1,3"] |=== -| MessageConverter | Description - -| `StringHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write `String` instances from the HTTP -request and response. By default, this converter supports all text media types -(`text/{asterisk}`) and writes with a `Content-Type` of `text/plain`. - -| `FormHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write form data from the HTTP -request and response. By default, this converter reads and writes the -`application/x-www-form-urlencoded` media type. Form data is read from and written into a -`MultiValueMap`. The converter can also write (but not read) multipart -data read from a `MultiValueMap`. By default, `multipart/form-data` is -supported. As of Spring Framework 5.2, additional multipart subtypes can be supported for -writing form data. Consult the javadoc for `FormHttpMessageConverter` for further details. - -| `ByteArrayHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write byte arrays from the -HTTP request and response. By default, this converter supports all media types (`{asterisk}/{asterisk}`) -and writes with a `Content-Type` of `application/octet-stream`. You can override this -by setting the `supportedMediaTypes` property and overriding `getContentType(byte[])`. - -| `MarshallingHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write XML by using Spring's -`Marshaller` and `Unmarshaller` abstractions from the `org.springframework.oxm` package. -This converter requires a `Marshaller` and `Unmarshaller` before it can be used. You can inject these -through constructor or bean properties. By default, this converter supports -`text/xml` and `application/xml`. - -| `MappingJackson2HttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write JSON by using Jackson's -`ObjectMapper`. You can customize JSON mapping as needed through the use of Jackson's -provided annotations. When you need further control (for cases where custom JSON -serializers/deserializers need to be provided for specific types), you can inject a custom `ObjectMapper` -through the `ObjectMapper` property. By default, this -converter supports `application/json`. +| Method group | Description -| `MappingJackson2XmlHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write XML by using -https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's -`XmlMapper`. You can customize XML mapping as needed through the use of JAXB -or Jackson's provided annotations. When you need further control (for cases where custom XML -serializers/deserializers need to be provided for specific types), you can inject a custom `XmlMapper` -through the `ObjectMapper` property. By default, this -converter supports `application/xml`. +| `getForObject` +| Retrieves a representation via GET. -| `SourceHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write -`javax.xml.transform.Source` from the HTTP request and response. Only `DOMSource`, -`SAXSource`, and `StreamSource` are supported. By default, this converter supports -`text/xml` and `application/xml`. +| `getForEntity` +| Retrieves a `ResponseEntity` (that is, status, headers, and body) by using GET. -| `BufferedImageHttpMessageConverter` -| An `HttpMessageConverter` implementation that can read and write -`java.awt.image.BufferedImage` from the HTTP request and response. This converter reads -and writes the media type supported by the Java I/O API. +| `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. -[[rest-template-jsonview]] -=== Jackson JSON Views +| `postForObject` +| Creates a new resource by using POST and returns the representation from the response. -You can specify a https://www.baeldung.com/jackson-json-view-annotation[Jackson JSON View] -to serialize only a subset of the object properties, as the following example shows: +| `postForEntity` +| Creates a new resource by using POST and returns the representation from the response. -[source,java,indent=0,subs="verbatim,quotes"] ----- - MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23")); - value.setSerializationView(User.WithoutPasswordView.class); +| `put` +| Creates or updates a resource by using PUT. - RequestEntity requestEntity = - RequestEntity.post(new URI("https://example.com/user")).body(value); +| `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. - ResponseEntity response = template.exchange(requestEntity, String.class); ----- +| `delete` +| Deletes the resources at the specified URI by using DELETE. -[[rest-template-multipart]] -=== Multipart +| `optionsForAllow` +| Retrieves allowed HTTP methods for a resource by using ALLOW. -To send multipart data, you need to provide a `MultiValueMap` 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: +| `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`. -[source,java,indent=0,subs="verbatim,quotes"] ----- - MultiValueMap parts = new LinkedMultiValueMap<>(); +These methods allow the use of `ParameterizedTypeReference` instead of `Class` to specify +a response type with generics. - parts.add("fieldPart", "fieldValue"); - parts.add("filePart", new FileSystemResource("...logo.png")); - parts.add("jsonPart", new Person("Jason")); +| `execute` +| The most generalized way to perform a request, with full control over request +preparation and response extraction through callback interfaces. - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_XML); - parts.add("xmlPart", new HttpEntity<>(myBean, headers)); ----- +|=== -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. +=== Initialization -Once the `MultiValueMap` is ready, you can pass it to the `RestTemplate`, as show below: +`RestTemplate` uses the same HTTP library abstraction as `RestClient`. +By default, it uses the `SimpleClientHttpRequestFactory`, but this can be changed via the constructor. +See <>. -[source,java,indent=0,subs="verbatim,quotes"] ----- - MultiValueMap parts = ...; - template.postForObject("https://example.com/upload", parts, Void.class); ----- +NOTE: `RestTemplate` can be instrumented for observability, in order to produce metrics and traces. +See the xref:integration/observability.adoc#http-client.resttemplate[RestTemplate Observability support] section. -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` is defaulted to `application/x-www-form-urlencoded`. -If necessary the `Content-Type` may also be set explicitly. +[[rest-template-body]] +=== Body +Objects passed into and returned from `RestTemplate` methods are converted to and from HTTP messages with the help of an `HttpMessageConverter`, see <>. [[rest-http-interface]] == HTTP Interface