Search This Blog

Saturday, 15 June 2013

Using Spring's RestTemplate class

In an earlier post we saw how to work create REST services using Spring. For testing the same we used a RESTClient Plugin available with Firefox.
It is often the case that we need our test code to be in Java so that it can be reused by others too. Spring provides us with an easy to use Rest Service client that can be used in our code.
The first step would be to configure our client:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>
From the code docs:
The central class for client-side HTTP access. It simplifies 
communication with HTTP servers, and enforces RESTful principles.
It handles HTTP connections, leaving application code to provide 
URLs (with possible template variables) and extract results.
True to its docs, the class does wrap lot of the code related to HTTP and allows us to focus on the operations exposed by the REST API. I first decided to test the retrieve record methods of the user resource:
@Component(value = "userRestClient")
public class UserRestClient {

   @Autowired
   private RestTemplate restTemplate;

   private final static String userServiceUrl = "http://localhost:8080/SampleRest/api/user/";

   public User getUser(final int id) {
      return this.restTemplate.getForObject(userServiceUrl + "{id}",
            User.class, id);
   }

   public static void main(final String[] args) {
      final ApplicationContext appContext = new ClassPathXmlApplicationContext(
            "client.xml");
      final UserRestClient restClient = (UserRestClient) appContext
            .getBean("userRestClient");
      final User user = restClient.getUser(1);
      System.out.println(user.getName() + " is of age " + user.getAge());
   }
}
The method uses the getForObject call to retrieve a User record. The URL as we saw earlier needs the id to be placed at the end. The restClient allows us to use the parametrized URL, taking care of generating the actual URL and making the call. The object returned is of type as specified by the class parameter. The third parameter is a var-args method that is used to specify the values to replace in the URL. The log indicates a successful run:
2013-06-15 17:31:33 DEBUG RestTemplate:78 - Created GET request for "http://loca
lhost:8080/SampleRest/api/user/1"
2013-06-15 17:31:33 DEBUG RestTemplate:528 - Setting request Accept header to [a
pplication/json]
2013-06-15 17:31:33 DEBUG RestTemplate:473 - GET request for "http://localhost:8
080/SampleRest/api/user/1" resulted in 200 (OK)
2013-06-15 17:31:33 DEBUG RestTemplate:78 - Reading [com.test.controller.User] a
s "application/json;charset=UTF-8" using [org.springframework.http.converter.jso
n.MappingJacksonHttpMessageConverter@18ce14a]
William is of age 12
In the above method we directly got access to the User object. However it could often be the case that we need to access the response headers. Or check if the response returned expected Status.
For this we have the ResponseEntity.
public User getUser(final String name) {
      final HashMap<String, String> urlVariables = new HashMap<String, String>(
            1);
      urlVariables.put("name", name);
      final String urlTemplate = userServiceUrl + "search/{name}";
      final ResponseEntity<User> responseEntity = this.restTemplate
            .getForEntity(urlTemplate, User.class, urlVariables);

      System.out.println("Response Status : " + responseEntity.getStatusCode());

      final HttpHeaders headers = responseEntity.getHeaders();
      System.out.println("headers in response are : " + headers);
      return responseEntity.getBody();
   }
I tested the same:
      User user = restClient.getUser("William");
      System.out.println(user.getName() + " has id " + user.getId()
            + " is of age " + user.getAge());
The output indicates the below:
Response Status : 200
headers in response are : {Server=[Apache-Coyote/1.1], Content-Type=[application
/json;charset=UTF-8], Transfer-Encoding=[chunked], Date=[Sat, 15 Jun 2013 12:17:
41 GMT]}
William has id 1 is of age 12
Here instead of dealing with the output object only, we have retrieved a representation of the HTTP response. The responseEntity class gives us access to headers and Status while the getBody method gives the output object. This object is generated by Spring's message converters from the actual response stream.
To test the Create User operation:
public User createUser(final User user) {
      return this.restTemplate.postForObject(userServiceUrl, user, User.class);
   }
The postForObject works similar to getForObject(). Only difference is that the second parameter here is the object that is written to the RequestStream. To test this method:
   User user = new User();
   user.setAge(21);
   user.setName("Robin");
   user = restClient.createUser(user);
   System.out.println("User created with id " + user.getId());
The output is :
013-06-15 17:53:16 DEBUG RestTemplate:78 - Created POST request for "http://loc
alhost:8080/SampleRest/api/user/"
2013-06-15 17:53:16 DEBUG RestTemplate:528 - Setting request Accept header to [a
pplication/json]
2013-06-15 17:53:16 DEBUG RestTemplate:592 - Writing [com.test.controller.User@1
114460] using [org.springframework.http.converter.json.MappingJacksonHttpMessage
Converter@9ffe3f]
2013-06-15 17:53:17 DEBUG RestTemplate:473 - POST request for "http://localhost:
8080/SampleRest/api/user/" resulted in 200 (OK)
2013-06-15 17:53:17 DEBUG RestTemplate:78 - Reading [com.test.controller.User] a
s "application/json;charset=UTF-8" using [org.springframework.http.converter.jso
n.MappingJacksonHttpMessageConverter@9ffe3f]
User created with id 3
Similarly for update and delete operations we have the below methods:
public void updateUser(final User user) {
      this.restTemplate.put(userServiceUrl + "{id}", user, user.getId());
   }

   public void deleteUser(final int id) {
      this.restTemplate.delete(userServiceUrl + "{id}", id);
   }
The two methods both have a void return type. However both PUT and DELETE are capable of returning response body. The RestTemplate does not support the same (I used Spring version 3.1.2) There is also the case where you may want to send some custom headers in the request. For that we need to use an instance of HttpEntity:
public void postWithHeaders(User user) {
      final HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.APPLICATION_JSON);
      headers.add("custom", true + "");

      final HttpEntity<User> wineRequest = new HttpEntity<User>(user, headers);
      user = this.restTemplate.postForObject(userServiceUrl, wineRequest,
            User.class);
   }
Interestingly the ResponseEntity class that we used earlier extends from HttpEntity. Just to add - it is not a must to use this class.We could probably achieve the same using the tried and tested HttpClient from Apache.
Spring's RestTemplate class is simply one more way to create a REST client. I did find it easy to use though.

5 comments:

  1. Very useful..Thanks!!

    ReplyDelete
  2. Can I pass extra custom headers in restTemplate getForEntity method..How can I do that

    ReplyDelete
  3. http://blog.tzolov.net/2010/03/spring-3-resttemplate-access-to-request.html


    final MultiValueMap headers = new LinkedMultiValueMap();
    headers.add("h1", h1);
    headers.add("h2", h2);
    final HttpEntity request = new HttpEntity(yourRequestObject, headers);

    restTemplate.postForObject("http://localhost:8080/service", request,
    YourResponseObject.class);

    ReplyDelete
  4. useful in deed...thanks for the article

    ReplyDelete