Using RestTemplate in Spring

Using RestTemplate in Spring

0 Comments

1. RestTemplate Introduction

In today’s blog post we will have a look at Springs well-known rest client – the RestTemplate. The RestTemplate is the central class within the Spring framework for executing synchronous HTTP requests on the client side.

Like Spring JdbcTemplate, RestTemplate is also a high-level API, which in turn is based on an HTTP client. By default, the class java.net.HttpURLConnection from the Java SDK is used in RestTemplate. However, the Spring Framework makes it possible to easily switch to another HTTP client API. How to do this is described in another blog post.

Most of us surely have experience with HttpURLConnection or another HTTP client API. When using it we noticed that for each request the same boilerplate code is generated again and again:

  • Creating a URL object and opening the connection
  • Configuring the HTTP request
  • Executing the HTTP request
  • Interpretation of the HTTP response
  • Converting the HTTP response into a Java object
  • Exception handling

When using RestTemplate all these things happen in the background and the developer doesn’t have to bother with it.

Starting with Spring 5, the non-blocking and reactive WebClient offers a modern alternative to RestTemplate. WebClient offers support for both synchronous and asynchronous HTTP requests and streaming scenarios. Therefore, RestTemplate will be marked as deprecated in a future version of the Spring Framework and will not contain any new functionalities.

2. Project Setup

Before we really get started, I would like to take a closer look at the following points of the project setup:

  • Used dependencies
  • POJO class Employee
  • REST web service for testing

2.1 Used Dependencies

For the RestTemplate demo project we need the following dependencies in our Spring Boot based application:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

The Dependency spring-boot-starter-web is a starter for building web applications. This dependency contains the class RestTemplate, the option to publish REST web services and many other web-related things.

As HTTP client API we use Apache HttpComponents for the following examples. Lombok generates e.g. Getter and Setter and helps us to avoid repeating code.

2.2 POJO Class Employee

Our POJO class, which will accompany us through the example, looks like this:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

  private long id;
  private String firstName;
  private String lastName;
  private long yearlyIncome;

}

Thanks to Lombok and @Data Annotation we get the getter and setter methods for free. Furthermore, @Data generates the following methods automatically:

  • equals()
  • hashCode()
  • toString()
  • Constructor with all fields that are annotated with @NonNull

@NoArgsConstructor generates a parameterless constructor and @AllArgsConstructor generates a constructor with all parameters.

2.3 REST Web Service For Testing

In order to better understand the following examples, the demo project includes a very handy REST web service. The corresponding RestController is guru.springframework.resttemplate.web.EmployeeRestController. The code for the controller is kept very simple and functional.

The REST web service provides the possibility to create, read, update and delete employee resources and supports the HTTP verbs GET, POST, PUT and DELETE. As soon as the application is stopped, all changes made to the resources are lost. The Web service is available at the endpoint http://localhost:8080/rest/employees.

3. RestTemplate Methods

Before we look at the first source code together, we take a look at the methods of the RestTemplate class. The class provides over 50 methods, most of them are overloaded several times. The following table gives a rough overview:

MethodDescription
void deleteExecutes a DELETE request and returns nothing.
ResponseEntity<T> exchangeExecutes a specified HTTP method, such as GET or POST, and returns a ResponseEntity that contains both the HTTP status code and the resource as an object.
T executeWorks similar to exchange, but expects an additional RequestCallback and a ResultSetExtractor as parameters. This is useful, for example, if you frequently create complex requests or want to process complex responses.
ResponseEntity<T> getForEntityExecutes a GET request and returns a ResponseEntity that contains both the status code and the resource as an object.
T getForObjectWorks similar to getForEntity, but returns the resource directly.
HttpHeaders headForHeadersExecutes a HEAD request and returns all HTTP headers for the specified URL.
Set<HttpMethod> optionsForAllowExecutes an OPTIONS request and uses the Allow header to return which HTTP methods are allowed under the specified URL.
T patchForObjectExecutes a PATCH request and returns the representation of the resource from the response. The JDK HttpURLConnection does not support PATCH, but Apache HttpComponents and others do.
ResponseEntity<T> postForEntityExecutes a POST request and returns a ResponseEntity which contains the status code as well as the resource as an object.
URI postForLocationWorks like postForEntity, but returns the Location header from the response, which indicates under which URI the newly created resource can be reached.
T postForObjectWorks like postForEntity, but returns the resource directly.
void putExecutes a PUT request and returns nothing.

Most of the methods are overloaded according to the following scheme:

  • URL as String and URL parameters as VarArgs of type String
  • URL as String and URL parameters as Map<String, String>
  • URL as java.net.URI without support for URL parameters

Each method with a return type expects a generic class type as a parameter to determine the type of response.

4. RestTemplate Demonstrations

The following examples show how we can consume a REST web service using the RestTemplate class. All of the following examples are in the EmployeeRestClient class. It’s a simple client that wraps RestTemplate and provides Employee-related methods. As always, you can find the code in our GitHub Repository.

public class EmployeeRestClient {

  private static final String RESOURCE_PATH = "/rest/employees";

  private Logger LOG = LoggerFactory.getLogger(EmployeeRestClient.class);
  private String REQUEST_URI;
  private RestTemplate restTemplate;

  public EmployeeRestClient(RestTemplate restTemplate, String host, int port) {
    this.restTemplate = restTemplate;
    this.REQUEST_URI = host + ":" + port + RESOURCE_PATH;
  }

}

So far the EmployeeRestClient is quite unspectacular. We get an instance of the RestTemplate from the constructor. Also via constructor parameters, we get the host and the port on which the REST web service runs.

Important: All following examples use Apache HttpComponents as underlying HTTP client API. How this can be configured for the RestTemplate is explained in the post Using RestTemplate with Apaches HttpClient.

4.1 GET

4.1.1 getForEntity()

Let’s start with a simple example to query a single resource:

public ResponseEntity<Employee> getForEntity(long id) {
  ResponseEntity<Employee> entity = restTemplate.getForEntity(REQUEST_URI + "/{id}",
                                                              Employee.class,
                                                              Long.toString(id));

  LOG.info("Status code value: " + entity.getStatusCodeValue());
  LOG.info("HTTP Header 'ContentType': " + entity.getHeaders().getContentType());

  return entity;
}

In this code snippet, we use the getForEntity() method, which returns a ResponseEntity object as a result. As a parameter, the method expects the URI of the resource including any placeholders and the class type for converting the body.

ResponseEntity encapsulates the status code of the HTTP response, the HTTP headers and the body that has already been converted into a Java object.

Instead of querying a single resource, it is of course also possible to query a collection of resources, as the following code snippet shows:

public List<Employee> getAll(int page, int pageSize) {
  String requestUri = REQUEST_URI + "?page={page}&pageSize={pageSize}";

  Map<String, String> urlParameters = new HashMap<>();
  urlParameters.put("page", Integer.toString(page));
  urlParameters.put("pageSize", Long.toString(pageSize));

  ResponseEntity<Employee[]> entity = restTemplate.getForEntity(requestUri,
                                                                Employee[].class,
                                                                urlParameters);

  return entity.getBody() != null? Arrays.asList(entity.getBody()) :                          
                                   Collections.emptyList();
}

The REST web service expects a page number and a pageSize (number of resources per page) as query parameters for querying a collection of resources. For these parameters, a Map is used in this code snippet instead of VarArgs. The ResponseEntity is typed to an array of Employee since we expect an undefined number of employees in the result.

4.1.2 getForObject()

If only the body is of interest, the getForObject() method can be used to query the resource directly as a Java object:

public Optional<Employee> getForObject(long id) {
  Employee employee = restTemplate.getForObject(REQUEST_URI + "/{id}",
                                                Employee.class,
                                                Long.toString(id));

  return Optional.ofNullable(employee);
}

However, if you want to operate directly on the JSON string, this is also possible. If the class type is simply String.class, we get the raw JSON string:

public JsonNode getAsJsonNode(long id) throws IOException {
  String jsonString = restTemplate.getForObject(REQUEST_URI + "/{id}",
                                                String.class,
                                                id);
  ObjectMapper mapper = new ObjectMapper();
  return mapper.readTree(jsonString);
}

Via ObjectMapper we can simply transform the JSON string into a JsonNode and then access the individual nodes of the JsonNode very comfortably via jsonNode.path("fieldName"):

@Test
void test_getAsJsonNode() throws Exception {
  JsonNode jsonNode = client.getAsJsonNode(3);

  assertNotNull(jsonNode);
  assertEquals(peterGrey.getId(), jsonNode.path("id").asLong());
  assertEquals(peterGrey.getFirstName(), jsonNode.path("firstName").asText());
  assertEquals(peterGrey.getLastName(), jsonNode.path("lastName").asText());
  assertEquals(peterGrey.getYearlyIncome(), jsonNode.path("yearlyIncome").asLong());
}

4.2 POST

4.2.1 postForObject()

The creation of a new resource via POST is possible with a one-liner:

public Employee postForObject(Employee newEmployee) {
  return restTemplate.postForObject(REQUEST_URI, newEmployee, Employee.class);
}

In addition to the request URI, the method postForObject() expects any object that represents the body of the request and a class type for the conversion of the response. As a response, the REST web service returns the created resource including the assigned ID.

4.2.2 postForLocation()

Very similar to postForObject works the method postForLocation(). Here we only get the URI of the new resource instead of the created resource:

public URI postForLocation(Employee newEmployee) {
  return restTemplate.postForLocation(REQUEST_URI, newEmployee);
}

4.2.3 postForEntity()

And finally there is postForEntity, which returns a ResponseEntity. Additionally, the example shows us how we can send our own values in the HTTP header to the server:

public ResponseEntity<Employee> postForEntity(Employee newEmployee) {
  MultiValueMap<String, String> headers = new HttpHeaders();
  headers.add("User-Agent", "EmployeeRestClient demo class");
  headers.add("Accept-Language", "en-US");

  HttpEntity<Employee> entity = new HttpEntity<>(newEmployee, headers);

  return restTemplate.postForEntity(REQUEST_URI, entity, Employee.class);
}

4.3 PUT

The method put() is used for an HTTP PUT. The return of the method is void. We can use this method to update an employee resource:

public void put(Employee updatedEmployee) {
  restTemplate.put(REQUEST_URI + "/{id}",
                   updatedEmployee,
                   Long.toString(updatedEmployee.getId()));
}

However, there are some use cases where we would like to have a ResponseEntity as a response since this gives us information about the HTTP status code and the HTTP headers sent along by the server. In this case, we can use the method exchange():

public ResponseEntity<Employee> putWithExchange(Employee updatedEmployee) {
  return restTemplate.exchange(REQUEST_URI + "/{id}",
                               HttpMethod.PUT,
                               new HttpEntity<>(updatedEmployee),
                               Employee.class,
                               Long.toString(updatedEmployee.getId()));
}

4.4 DELETE

The method delete() is used to execute a DELETE request:

public void delete(long id) {
  restTemplate.delete(REQUEST_URI + "/{id}", Long.toString(id));
}

Here again the same as with put(). If the HTTP status code or the HTTP headers are of interest, the method exchange() must be used:

public ResponseEntity<Void> deleteWithExchange(long id) {
  return restTemplate.exchange(REQUEST_URI + "/{id}",
                               HttpMethod.DELETE,
                               null,
                               Void.class,
                               Long.toString(id));
}

Since the server doesn’t return anything to us we use Void.class as the type for response body conversion.

4.5 HEAD

If only the HTTP headers of an HTTP request are of interest, we use method headForHeaders():

public HttpHeaders headForHeaders() {
  return restTemplate.headForHeaders(REQUEST_URI);
}

A test of this method confirms that we receive a response with the content type application/json when we query the specified URL:

@Test
void test_headForHeaders() {
  HttpHeaders httpHeaders = client.headForHeaders();

  assertNotNull(httpHeaders.getContentType());
  assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
}

4.6 OPTIONS

With a query via HTTP OPTIONS, we can find out which HTTP verbs are allowed for the given URL. RestTemplate provides the optionsForAllow() method for this:

public Set<HttpMethod> optionsForAllow(long id) {
  return restTemplate.optionsForAllow(REQUEST_URI + "/{id}", Long.toString(id));
}

A test of this method confirms that we can query the URL http://localhost:8080/rest/employees/1 with the HTTP verbs GET, PUT and DELETE:

@Test
void test_optionsForAllow() {
  Set<HttpMethod> httpMethods = client.optionsForAllow(1);
  List<HttpMethod> expectedHttpMethods = List.of(HttpMethod.GET, 
                                                 HttpMethod.PUT, 
                                                 HttpMethod.DELETE);

  assertTrue(httpMethods.containsAll(expectedHttpMethods));
}

5. Summary

In this blog post, we looked at how we work with the class RestTemplate. We looked at the following:

  • a general overview of RestTemplate and its methods
  • numerous code examples for the following HTTP verbs:
    • GET
    • POST
    • PUT
    • DELETE
    • HEAD
    • OPTIONS

Also, like to check out the project repository at GitHub. There you’ll also find a test class, which we didn’t discuss in detail here.

I would also like to draw your attention to the blog post Using RestTemplate with Apaches HttpClient. In this post, we take a look at how to configure RestTemplate to use it with the HTTP client API of Apache.

About Daniel Wagner

My name is Daniel and I'm a passionate Java developer. Most of my free time is devoted to training in new and exciting topics that the Java ecosystem has to offer.

You May Also Like