This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Framework 6.0.26!

REST Clients

The Spring Framework provides the following choices for making calls to REST endpoints:

  • WebClient - non-blocking, reactive client with fluent API.

  • RestTemplate - synchronous client with template method API.

  • HTTP Interface - annotated interface with generated, dynamic proxy implementation.

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.

See WebClient for more details.

RestTemplate

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:

RestTemplate is in maintenance mode, with only requests for minor changes and bugs to be accepted. Please, consider using the WebClient instead.
Table 1. RestTemplate methods
Method group Description

getForObject

Retrieves a representation via GET.

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.

put

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.

Initialization

The default constructor uses java.net.HttpURLConnection to perform requests. You can switch to a different HTTP library with an implementation of ClientHttpRequestFactory. Currently, there is also built-in support for Apache HttpComponents and OkHttp.

For example, to switch to Apache HttpComponents, you can use the following:

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());

Each ClientHttpRequestFactory exposes configuration options specific to the underlying HTTP client library — for example, for credentials, connection pooling, and other details.

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.
RestTemplate can be instrumented for observability, in order to produce metrics and traces. See the RestTemplate Observability support section.

URIs

Many of the RestTemplate methods accept a URI template and URI template variables, either as a String variable argument, or as Map<String,String>.

The following example uses a String variable argument:

String result = restTemplate.getForObject(
		"https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");

The following example uses a Map<String, String>:

Map<String, String> vars = Collections.singletonMap("hotel", "42");

String result = restTemplate.getForObject(
		"https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);

Keep in mind URI templates are automatically encoded, as the following example shows:

restTemplate.getForObject("https://example.com/hotel list", String.class);

// Results in request to "https://example.com/hotel%20list"

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.

For more details on working with and encoding URIs, see URI Links.

Headers

You can use the exchange() methods to specify request headers, as the following example shows:

String uriTemplate = "https://example.com/hotels/{hotel}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);

RequestEntity<Void> requestEntity = RequestEntity.get(uri)
		.header("MyRequestHeader", "MyValue")
		.build();

ResponseEntity<String> response = template.exchange(requestEntity, String.class);

String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();

You can obtain response headers through many RestTemplate method variants that return ResponseEntity.

Body

Objects 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, as the following example shows:

URI location = template.postForLocation("https://example.com/people", person);

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.

On a GET, the body of the response is deserialized to an output Object, as the following example shows:

Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42);

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 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.

Message Conversion

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).

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 Configuring Message Converters).

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:

Table 2. HttpMessageConverter Implementations
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/*) 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<String, String>. The converter can also write (but not read) multipart data read from a MultiValueMap<String, Object>. 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 (*/*) 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.

MappingJackson2XmlHttpMessageConverter

An HttpMessageConverter implementation that can read and write XML by using 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.

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.

Jackson JSON Views

You can specify a Jackson JSON View to serialize only a subset of the object properties, as the following example shows:

MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);

RequestEntity<MappingJacksonValue> requestEntity =
	RequestEntity.post(new URI("https://example.com/user")).body(value);

ResponseEntity<String> response = template.exchange(requestEntity, String.class);

Multipart

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));

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 pass it to the RestTemplate, as show below:

MultiValueMap<String, Object> parts = ...;
template.postForObject("https://example.com/upload", parts, Void.class);

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.

HTTP Interface

The Spring Framework lets you define an HTTP service as a Java interface with annotated methods for HTTP exchanges. You can then generate a proxy that implements this interface and performs the exchanges. This helps to simplify HTTP remote access which often involves a facade that wraps the details of using the underlying HTTP client.

One, declare an interface with @HttpExchange methods:

interface RepositoryService {

	@GetExchange("/repos/{owner}/{repo}")
	Repository getRepository(@PathVariable String owner, @PathVariable String repo);

	// more HTTP exchange methods...

}

Two, create a proxy that will perform the declared HTTP exchanges:

WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).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);

}

Method Parameters

Annotated, HTTP exchange methods support flexible method signatures with the following method parameters:

Method argument Description

URI

Dynamically set the URL for the request, overriding the annotation’s url attribute.

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.

@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.

@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, e.g. as JSON), HttpEntity (part content and headers), a Spring Part, or Reactive Streams Publisher of any of the above.

@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.

Return Values

Annotated, HTTP exchange methods support the following return values:

Method return value Description

void, Mono<Void>

Perform the given request, and release the response content, if any.

HttpHeaders, Mono<HttpHeaders>

Perform the given request, release the response content, if any, and return the response headers.

<T>, Mono<T>

Perform the given request and decode the response content to the declared return type.

<T>, Flux<T>

Perform the given request and decode the response content to a stream of the declared element type.

ResponseEntity<Void>, Mono<ResponseEntity<Void>>

Perform the given request, and release the response content, if any, and return a ResponseEntity with the status and headers.

ResponseEntity<T>, 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.

You can also use any other async or reactive types registered in the ReactiveAdapterRegistry.

Exception Handling

By default, WebClient raises WebClientResponseException for 4xx and 5xx HTTP status codes. To customize this, you can register a response status handler that applies to all responses performed through the client:

WebClient webClient = WebClient.builder()
		.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
		.build();

WebClientAdapter clientAdapter = WebClientAdapter.forClient(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory
		.builder(clientAdapter).build();

For more details and options, such as suppressing error status codes, see the Javadoc of defaultStatusHandler in WebClient.Builder.