From d007c25585517d59be4d72a5004f837a9e1205d3 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 23 Mar 2018 19:00:46 -0400 Subject: [PATCH] Improve docs on RestTemplate In preparation for adding multipart content. Issue: SPR-16635 --- src/docs/asciidoc/integration.adoc | 464 +++++++++++++---------------- 1 file changed, 211 insertions(+), 253 deletions(-) diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index 4399379b76..d980f396c8 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -946,9 +946,9 @@ plugging in third-party or custom solutions here. [[rest-client-access]] -=== Accessing REST endpoints +=== REST Endpoints -The Spring Framework has two choices for client-side access to REST endpoints: +The Spring Framework provides two choices for making calls to REST endpoints: * <> -- the original Spring REST client with an API similar to other template classes in Spring such as `JdbcTemplate`, `JmsTemplate` and others. @@ -963,130 +963,75 @@ to support high concurrency more efficiently (i.e. using a small number of threa [[rest-resttemplate]] ==== RestTemplate -The `RestTemplate` provides a higher level API over HTTP client libraries with methods -that correspond to each of the six main HTTP methods that make invoking many RESTful -services a one-liner and enforce REST best practices. - +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: [[rest-overview-of-resttemplate-methods-tbl]] -.Overview of RestTemplate methods +.RestTemplate methods [cols="1,3"] |=== -| HTTP Method | RestTemplate Method +| Method group | Description -| DELETE -| {api-spring-framework}/web/client/RestTemplate.html#delete(String,%20Object...)[delete] +| `getForObject` +| Retrieve a representation via GET. -| GET -| {api-spring-framework}/web/client/RestTemplate.html#getForObject(String,%20Class,%20Object...)[getForObject] - {api-spring-framework}/web/client/RestTemplate.html#getForEntity(String,%20Class,%20Object...)[getForEntity] +| `getForEntity` +| Retrieve a `ResponseEntity`, i.e. status, headers, and body, via GET. -| HEAD -| {api-spring-framework}/web/client/RestTemplate.html#headForHeaders(String,%20Object...)[headForHeaders(String - url, String... uriVariables)] +| `headForHeaders` +| Retrieve all headers for a resource via HEAD. -| OPTIONS -| {api-spring-framework}/web/client/RestTemplate.html#optionsForAllow(String,%20Object...)[optionsForAllow(String - url, String... uriVariables)] +| `postForLocation` +| Create a new resource via POST and return the Location header from the response. -| POST -| {api-spring-framework}/web/client/RestTemplate.html#postForLocation(String,%20Object,%20Object...)[postForLocation(String - url, Object request, String... uriVariables)] - {api-spring-framework}/web/client/RestTemplate.html#postForObject(java.lang.String,%20java.lang.Object,%20java.lang.Class,%20java.lang.String...)[postForObject(String - url, Object request, Class responseType, String... uriVariables)] +| `postForObject` +| Create a new resource via POST and return the representation from the response. -| PUT -| {api-spring-framework}/web/client/RestTemplate.html#put(String,%20Object,%20Object...)[put(String - url, Object request, String...uriVariables)] +| `postForEntity` +| Create a new resource via POST and return the representation from the response. + +| `put` +| Create or update a resource via PUT. + +| `patchForObject` +| Update a resource via PATCH and return the representation from the response. +Note that the JDK `HttpURLConnection` does not support the `PATCH` but Apache +HttpComponents, and others do. + +| `delete` +| Delete the resources at the specified URI via DELETE. + +| `optionsForAllow` +| Retrieve allowed HTTP methods for a resource via ALLOW. + +| `exchange` +| More generalized, and less opinionated version, of the above methods that provides extra +flexibility when needed. It accepts `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 via callback interfaces. -| PATCH and others -| {api-spring-framework}/web/client/RestTemplate.html#exchange(java.lang.String,%20org.springframework.http.HttpMethod,%20org.springframework.http.HttpEntity,%20java.lang.Class,%20java.lang.Object...)[exchange] - {api-spring-framework}/web/client/RestTemplate.html#execute(java.lang.String,%20org.springframework.http.HttpMethod,%20org.springframework.web.client.RequestCallback,%20org.springframework.web.client.ResponseExtractor,%20java.lang.Object...)[execute] |=== -The names of `RestTemplate` methods follow a naming convention, the first part indicates -what HTTP method is being invoked and the second part indicates what is returned. For -example, the method `getForObject()` will perform a GET, convert the HTTP response into -an object type of your choice and return that object. The method `postForLocation()` -will do a POST, converting the given object into a HTTP request and return the response -HTTP Location header where the newly created object can be found. In case of an -exception processing the HTTP request, an exception of the type `RestClientException` -will be thrown; this behavior can be changed by plugging in another -`ResponseErrorHandler` implementation into the `RestTemplate`. -The `exchange` and `execute` methods are generalized versions of the more specific -methods listed above them and can support additional combinations and methods, -e.g. HTTP PATCH. However, note that the underlying HTTP library must also support the -desired combination. The JDK `HttpURLConnection` does not support the `PATCH` method -but Apache HttpComponents HttpClient version 4.2 or later does. They also enable -`RestTemplate` to read an HTTP response to a generic type (e.g. `List`), -using a `ParameterizedTypeReference`, a new class that enables capturing and passing -generic type info. +[[rest-resttemplate-create]] +===== Initialization -Objects passed to and returned from these methods are converted to and from HTTP -messages by `HttpMessageConverter` implementations. Converters for the main MIME types -are registered by default, but you can also override the defaults and register custom -converters via the `messageConverters()` bean property. The default converters are -`ByteArrayHttpMessageConverter`, `StringHttpMessageConverter`, -`ResourceHttpMessageConverter`, `SourceHttpMessageConverter` as well as -`AllEncompassingFormHttpMessageConverter` and a few provider-specific converters: -e.g. `MappingJackson2HttpMessageConverter` when Jackson is present on the classpath. +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: -Each method takes URI template arguments in two forms, either as a `String` -variable-length argument or a `Map`. For example, +* Apache HttpComponents +* Netty +* OkHttp -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - String result = restTemplate.getForObject( - "http://example.com/hotels/{hotel}/bookings/{booking}", String.class,"42", "21"); ----- - -using variable-length arguments and - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Map vars = Collections.singletonMap("hotel", "42"); - String result = restTemplate.getForObject( - "http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); ----- - -using a `Map`. - -To create an instance of `RestTemplate` you can simply call the default no-arg -constructor. This will use standard Java classes from the `java.net` package as the -underlying implementation to create HTTP requests. This can be overridden by specifying -an implementation of `ClientHttpRequestFactory`. Spring provides the implementation -`HttpComponentsClientHttpRequestFactory` that uses the Apache HttpComponents -`HttpClient` to create requests. `HttpComponentsClientHttpRequestFactory` is configured -using an instance of `org.apache.http.client.HttpClient` which can in turn be configured -with credentials information or connection pooling functionality. - -[TIP] -==== -Note that the `java.net` implementation for HTTP requests may raise an exception when -accessing the status of a response that represents an error (e.g. 401). If this is an -issue, switch to `HttpComponentsClientHttpRequestFactory` instead. -==== - -The previous example using Apache HttpComponents `HttpClient` directly rewritten to use -the `RestTemplate` is shown below - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - uri = "http://example.com/hotels/{id}/bookings"; - - RestTemplate template = new RestTemplate(); - - Booking booking = // create booking object - - URI location = template.postForLocation(uri, booking, "1"); ----- - -To use Apache HttpComponents instead of the native `java.net` functionality, construct -the `RestTemplate` as follows: +For example to switch to Apache HttpComponents use: [source,java,indent=0] [subs="verbatim,quotes"] @@ -1094,76 +1039,65 @@ the `RestTemplate` as follows: RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); ---- +Each `ClientHttpRequestFactory` exposes configuration options specific to the underlying +HTTP client library, e.g. for credentials, connection pooling, etc. + [TIP] ==== -Apache HttpClient supports gzip encoding. To use it, -construct a `HttpComponentsClientHttpRequestFactory` like so: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - HttpClient httpClient = HttpClientBuilder.create().build(); - ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - RestTemplate restTemplate = new RestTemplate(requestFactory); ----- +Note that the `java.net` implementation for HTTP requests may raise an exception when +accessing the status of a response that represents an error (e.g. 401). If this is an +issue, switch to another HTTP client library. ==== -The general callback interface is `RequestCallback` and is called when the execute -method is invoked. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public T execute(String url, HttpMethod method, RequestCallback requestCallback, - ResponseExtractor responseExtractor, String... uriVariables) - - // also has an overload with uriVariables as a Map. ----- - -The `RequestCallback` interface is defined as - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface RequestCallback { - void doWithRequest(ClientHttpRequest request) throws IOException; - } ----- - -and allows you to manipulate the request headers and write to the request body. When -using the execute method you do not have to worry about any resource management, the -template will always close the request and handle any errors. Refer to the API -documentation for more information on using the execute method and the meaning of its -other method arguments. [[rest-resttemplate-uri]] -===== Working with the URI +===== URIs -For each of the main HTTP methods, the `RestTemplate` provides two variants that take -either a String URI template or `java.net.URI` as the first argument. When using a String -URI template, encoding is automatically applied: +Many of the `RestTemplate` methods accepts a URI template and URI template variables, +either as a `String` vararg, or as `Map`. + +For example with a `String` vararg: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + String result = restTemplate.getForObject( + "http://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21"); +---- + +Or with a `Map`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Map vars = Collections.singletonMap("hotel", "42"); + + String result = restTemplate.getForObject( + "http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); +---- + +Keep in mind URI templates are automatically encoded. For example: [source,java,indent=0] [subs="verbatim,quotes"] ---- restTemplate.getForObject("http://example.com/hotel list", String.class); + + // Results in request to "http://example.com/hotel%20list" ---- -The resulting target URI is "http://example.com/hotel%20list". Alternatively you can -provide an already prepared `java.net.URI` that will be used as is. For more information -on preparing URIs or customizing how the `RestTemplate` expands URI templates, see -<> in the "Web Servlet" section. +You can use the `uriTemplateHandler` property of `RestTemplate` to customize how URIs are +encoded. Or you can prepare a `java.net.URI` and pass it into one of the `RestTemplate` +methods that accept a `URI`. + +For more details on working with and encoding URIs, see +<>. [[rest-template-headers]] -===== Dealing with request and response headers +===== Headers -Besides the methods described above, the `RestTemplate` also has the `exchange()` -method, which can be used for arbitrary HTTP method execution based on the `RequestEntity` -class. - -Perhaps most importantly, the `exchange()` method can be used to add request headers and -read response headers. For example: +Use the `exchange()` methods to specify request headers. For example: [source,java,indent=0] [subs="verbatim,quotes"] @@ -1181,12 +1115,122 @@ read response headers. For example: String body = response.getBody(); ---- -In the above example, we first prepare a request entity that contains the -`MyRequestHeader` header. We then retrieve the response, and read the `MyResponseHeader` -and body. +Response headers can be obtained through many `RestTemplate` method variants that return +`ResponseEntity`. + + +[[rest-template-body]] +===== Body + +Object passed into and returned from `RestTemplate` methods are converted to and from raw +content with the help of an `HttpMessageConverter`. + +On a POST, an input object is serialized to the request body: + + URI location = template.postForLocation("http://example.com/people", person); + +The "Content-Type" header of the request does not need to be set explicitly. In most cases +a compatible message converter can be found based on the source Object type, and the chosen +message converter will set the content type accordingly. If necessary, you can use the +`exchange` methods to provide the "Content-Type" request header explicitly, and that in +turn will influence what message converter is selected. + +On a GET, the body of the response is deserialized to an output Object: + + Person person = restTemplate.getForObject("http://example.com/people/{id}", Person.class, 42); + +The "Accept" header of the request does not need to be set explicitly. 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 +<>, 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]#<># + +The `spring-web` module contains the `HttpMessageConverter` contract for reading and +writing the body of HTTP requests and responses via `InputStream` and `OutputStream`. +``HttpMessageConverter``'s are used on the client side, e.g. in the `RestTemplate`, and +also on the server side, e.g. in Spring MVC REST controllers. + +Concrete implementations for the main media (MIME) types are provided in the framework +and are registered by default with the `RestTemplate` on the client-side and with +`RequestMethodHandlerAdapter` on the server-side (see +<>). + +The implementations of ``HttpMessageConverter``s are described in the following sections. +For all converters a default media type is used but can be overridden by setting the +`supportedMediaTypes` bean property + +[[rest-message-converters-tbl]] +.HttpMessageConverter Implementations +[cols="1,3"] +|=== +| MessageConverter | Description + +| `StringHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write Strings 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 media type +`application/x-www-form-urlencoded`. Form data is read from and written into a +`MultiValueMap`. + +| `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`. This can be overridden +by setting the `supportedMediaTypes` property, and overriding `getContentType(byte[])`. + +| `MarshallingHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write XML 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. These +can be injected via constructor or bean properties. By default this converter supports ( +`text/xml`) and ( `application/xml`). + +| `MappingJackson2HttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write JSON using Jackson's +`ObjectMapper`. JSON mapping can be customized as needed through the use of Jackson's +provided annotations. When further control is needed, a custom `ObjectMapper` can be +injected through the `ObjectMapper` property for cases where custom JSON +serializers/deserializers need to be provided for specific types. By default this +converter supports ( `application/json`). + +| `MappingJackson2XmlHttpMessageConverter` +| An `HttpMessageConverter` implementation that can read and write XML using +https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's +`XmlMapper`. XML mapping can be customized as needed through the use of JAXB +or Jackson's provided annotations. When further control is needed, a custom `XmlMapper` +can be injected through the `ObjectMapper` property for cases where custom XML +serializers/deserializers need to be provided for specific types. By default this +converter supports ( `application/xml`). + +| `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`). + +| `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. + +|=== + [[rest-template-jsonview]] -===== Jackson JSON Views support +===== Jackson JSON Views It is possible to specify a http://wiki.fasterxml.com/JacksonJsonViews[Jackson JSON View] to serialize only a subset of the object properties. For example: @@ -1204,98 +1248,12 @@ to serialize only a subset of the object properties. For example: ---- -[[rest-message-conversion]] -==== HTTP Message Converters -[.small]#<># - -The `spring-web` module contains the `HttpMessageConverter` contract for reading and -writing the body of HTTP requests and responses via `InputStream` and `OutputStream`. -``HttpMessageConverter``'s are used on the client side, e.g. in the `RestTemplate`, and -also on the server side, e.g. in Spring MVC REST controllers. - -Concrete implementations for the main media (MIME) types are provided in the framework -and are registered by default with the `RestTemplate` on the client-side and with -`RequestMethodHandlerAdapter` on the server-side (see -<>). - -The implementations of ``HttpMessageConverter``s are described in the following sections. -For all converters a default media type is used but can be overridden by setting the -`supportedMediaTypes` bean property - -[[rest-string-converter]] -===== StringHttpMessageConverter - -An `HttpMessageConverter` implementation that can read and write Strings 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`. - -[[rest-form-converter]] -===== 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 media type -`application/x-www-form-urlencoded`. Form data is read from and written into a -`MultiValueMap`. - -[[rest-byte-converter]] -===== 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`. This can be overridden -by setting the `supportedMediaTypes` property, and overriding `getContentType(byte[])`. - -[[rest-marhsalling-converter]] -===== MarshallingHttpMessageConverter - -An `HttpMessageConverter` implementation that can read and write XML 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. These -can be injected via constructor or bean properties. By default this converter supports ( -`text/xml`) and ( `application/xml`). - -[[rest-mapping-json-converter]] -===== MappingJackson2HttpMessageConverter - -An `HttpMessageConverter` implementation that can read and write JSON using Jackson's -`ObjectMapper`. JSON mapping can be customized as needed through the use of Jackson's -provided annotations. When further control is needed, a custom `ObjectMapper` can be -injected through the `ObjectMapper` property for cases where custom JSON -serializers/deserializers need to be provided for specific types. By default this -converter supports ( `application/json`). - -[[rest-mapping-xml-converter]] -===== MappingJackson2XmlHttpMessageConverter - -An `HttpMessageConverter` implementation that can read and write XML using -https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML] extension's -`XmlMapper`. XML mapping can be customized as needed through the use of JAXB -or Jackson's provided annotations. When further control is needed, a custom `XmlMapper` -can be injected through the `ObjectMapper` property for cases where custom XML -serializers/deserializers need to be provided for specific types. By default this -converter supports ( `application/xml`). - -[[rest-source-converter]] -===== 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`). - -[[rest-buffered-image-converter]] -===== 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. - [[rest-async-resttemplate]] ==== Async RestTemplate -The `AsyncRestTemplate` is deprecated. -Please use the <> instead. +The `AsyncRestTemplate` is deprecated. For all use cases where the `AsyncRestTemplate` +is considered for use, please use the <> instead.