Representational state transfer (REST) is a very popular architecture for distributed hypermedia. Lots of different web services expose their APIs in a RESTful manner. It is very convenient when a service of choice provides a library for its API, but this is not always so. In this case, you have to construct valid requests and parse responses by yourself. Assuming that you are familiar with REST itself, I will tell you how you can make your life easier with the help of Spring and Java annotations.
Let’s consider a service that stores some accounts. To retrieve one, we must issue a request GET https://api.example.com/accounts/{id}
Providing “1” as the ID, we get something like this in the response body
<?xml version="1.0" encoding="UTF-8"?>
<account href="https:// api.example.com/accounts/1">
<id type="integer">1</id>
<username>tester</username>
<email>tester@ example.com</email>
<full_name>John Doe</full_name>
<created_at type="datetime">2011-10-25T12:00:00</created_at>
</account>Our goal is to map this data to a JavaBean and be able to GET and POST it back and forth. Doing such a task manually is very low-level, with all the consequences. You can use a ready solution, such as Spring RestTemplate for HTTP communications and JAXB for data binding.
Mapping a JavaBean to an XML element is as easy as putting @XmlRootElement on top of your class and annotating every field you want to be mapped with @XmlElement. If you put a bare annotation, then the name of the XML Schema element is derived from the JavaBean field name. If names don’t match, you can specify them with the “name” element.
@XmlRootElement(name = "account")
public class Account {
@XmlElement
private Integer id;
@XmlElement
private String username;
@XmlElement
private String email;
@XmlElement(name = "full_name")
private String fullName;
@XmlElement(name = "created_at")
private Date createdAt;
public Account() {}
/* Getters and setters */
}Issuing requests and receiving responses is not a single bit harder. All data binding occurs automatically.
RestTemplate rest = new RestTemplate();
Account account = rest.getForObject("https://api.example.com/accounts/1",
Account.class);First, you create a RestTemplate object, and then you invoke the appropriate methods against it. The first part of the method’s name indicates which HTTP method will be used, while the second part indicates what is returned. In this case, a GET is performed, the HTTP response is converted into an object type of Account, which is then returned. There are dedicated methods for each of the six main HTTP methods (DELETE, GET, HEAD, OPTIONS, POST, PUT) in RestTemplate.
Let’s make some changes to the entity’s state
account.setEmail("changed@ example.com");
URI uri = rest.postForLocation("https:// api.example.com/accounts/1", account);And delete it when it is no longer needed
rest.delete(uri);Now, suppose our service mandates authentication for using its API. For this purpose, it requires an API key to be present in the request headers. For such manipulations on the request, we must implement the ClientHttpRequestFactory interface and provide this object as a constructor parameter during RestTemplate initialization. Here’s an example of extending CommonsClientHttpRequestFactory
package com.sysgears.example;
import org.apache.commons.httpclient.HttpMethodBase;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
public class RequestWithHeadersFactory extends CommonsClientHttpRequestFactory {
private final String apiKey;
public RequestWithHeadersFactory(String apiKey) {
super();
this.apiKey = apiKey;
}
@Override
protected void postProcessCommonsHttpMethod(HttpMethodBase httpMethod) {
super.postProcessCommonsHttpMethod(httpMethod);
httpMethod.addRequestHeader("Accept", "application/xml");
httpMethod.addRequestHeader("Content-Type",
"application/xml; charset=utf-8");
httpMethod.addRequestHeader("Authorization", apiKey);
}
}Now the construction of RestTemplate looks like this
RestTemplate rest = new RestTemplate(new RequestWithHeadersFactory("mySecureKey"));And all subsequent requests will contain the above headers. This is it, working with REST should be as easy as rest.
