1. Introduction

Among the many parts of the Spring ecosystem is a class named RestTemplate. This utility is a high-level class for sending HTTP messages and handling the response back.

In this tutorial, we’ll look at the differences between the exchange(), postForEntity(), and execute() methods of the RestTemplate class.

2. What Is RestTemplate?

As mentioned above, RestTemplate is a utility class in Spring Framework that makes it simple to send HTTP messages and process the response. The RestTemplate class is great for writing simple HTTP clients as it provides a number of features:

  • Support for all standard HTTP verbs (GET, POST, etc)
  • Ability to work with all standard MIME types (JSON, XML, form-encoded, etc)
  • High-level API that allows us to work with Java classes and avoid complex serialization concerns
  • Customizable using ClientHttpRequestInitializer and ClientHttpRequestInterceptor interfaces

2.1. Deprecation Warning

As of Spring Framework 5, the RestTemplate class is slowly being deprecated. While it still exists in Spring Framework 6, the maintainers have made it clear there will be no future enhancements to this class.

Because only minor bug and security fixes will be accepted, developers are encouraged to use WebClient instead. This class has a more modern API and supports synchronous, asynchronous, and streaming use cases.

3. Basic RestTemplate Usage

RestTemplate makes it easy to use the standard HTTP verbs by providing public methods with the corresponding names.

For example, to send a GET request, we can use one of the many overloaded methods that have the getFor prefix. And there are similar public methods for other HTTP verbs, including POST, PUT, DELETE, HEAD, and PATCH.

The structure of all of these methods is nearly identical. They essentially only require information about the URL to send, as well as the representation for the request and response bodies. Information such as headers is automatically created for us.

While these high-level methods make it very easy to write HTTP clients, the real world doesn’t always behave like the HTTP specification. In some cases, we may need to construct a HTTP request that doesn’t perfectly fit one of the verb-specific methods.

This is why RestTemplate provides more generic methods with grain methods, which we’ll look at next.

4. Using the exchange(), postForEntity(), and execute() Methods

While using the top-level verb-specific methods is fine for many use cases, there will likely be times when we need more control over the HTTP request that is generated by RestTemplate. This is where the exchange() and execute() methods come in handy.

Let’s consider an example HTTP POST request that lets us create a new entry in a book database. Here’s a Java class that encapsulates all the data required for our request body:

class Book {
  String title;
  String author;
  int yearPublished;
}

Below we’ll use each of the three RestTemplate method varieties to send this request.

4.1. Using the postForEntity() Method

The first and simplest way to send a POST request is using postForEntity(). This method only requires the URL and request body and parses the response body into a ResponseEntity object:

Book book = new Book(
  "Cruising Along with Java",
  "Venkat Subramaniam",
  2023);

 ResponseEntity<Book> response = restTemplate.postForEntity(
  "https://api.bookstore.com", 
  book, 
  Book.class);

In this example, we created a new book object, sent it to the server, and parsed the response back into another book object. Notably, all we had to provide was the remote URL, the request object, and the class to use for the response. Everything else, including HTTP headers, was automatically constructed by RestTemplate.

4.2. Using the exchange() Method

The next way we can send our request is using the exchange() method:

Book book = new Book(
  "Effective Java",
  "Joshua Bloch",
  2001);

HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

ResponseEntity<Book> response = restTemplate.exchange(
  "https://api.bookstore.com",
  HttpMethod.POST,
  new HttpEntity<>(book, headers),
  Book.class);

The main difference here is that instead of passing a plain Java object as the request body, we wrap it with HttpEntity. This allows us to explicitly set additional HTTP headers with the request.

The other noticeable difference is that the exchange() method is generic, meaning it can be used for any HTTP method. Thus, the second parameter after the URL must indicate which method to use for the request.

4.3. Using the execute() Method

The final way we can send our POST request is by using the execute() method. This method is the most generic and, in fact, is the underlying method used by all other methods inside RestTemplate.

Below is a high-level sample of how to use the execute() method to send a POST request:

ResponseEntity<Book> response = restTemplate.execute(
    "https://api.bookstore.com",
    HttpMethod.POST,
    new RequestCallback() {
        @Override
        public void doWithRequest(ClientHttpRequest request) throws IOException {
            // manipulate request headers and body
        }
    },
    new ResponseExtractor<ResponseEntity<Book>>() {
        @Override
        public ResponseEntity<Book> extractData(ClientHttpResponse response) throws IOException {
            // manipulate response and return ResponseEntity
        }
    }
);

It’s worth noticing that while we still have to provide the URL and HTTP method, everything else looks vastly different. This is because the execute() method doesn’t deal directly with requests and responses.

Instead, it gives us the ability to create and modify them using the RequestCallback and ResponseExtractor interfaces, respectively. The main benefit is that this gives us the most control over the request and response objects. On the other hand, our code is less concise, and we lose many of the automatic features that other RestTemplate methods provide.

It’s also worth noting that RestTemplate does provide a factory method to easily create an instance of RequestCallback. The method is httpEntityCallback() and has two overloaded forms that can help reduce the amount of code we write when using the execute() method:

Book book = new Book(
  "Reactive Spring",
  "Josh Long",
  2020);
        
RequestCallback requestCallback1 = restTemplate.httpEntityCallback(book);
RequestCallback requestCallback2 = restTemplate.httpEntityCallback(book, Book.class);

Likewise, RestTemplate provides a factory method to quickly create an instance of ResponseExtractor:

ResponseExtractor<ResponseEntity<Book>> responseExtractor = restTemplate.responseEntityExtractor(Book.class);

Of course, using both of these factory methods would negate any benefit of using the execute() method. If we opted to use them both, we’d be better off just using the verb-specific or exchange() methods.

5. Conclusion

In this article, we looked at three different ways to send a HTTP POST request using RestTemplate. First, we saw how to use the verb-specific postForEntity() method to create small and concise HTTP requests. We then looked at two alternative methods, exchange() and execute(), to send the same request.

While all three methods yield the same result, they each came with pros and cons. The postForEntity() method resulted in less code, with the consequence that we had less control over the resulting HTTP request. The exchange() and execute() methods provided us more control over the request, at the expense of our code being more verbose and less reliant on automatic features of the Spring framework.

As always, the code examples above can be found over on GitHub.