REST in Spring 3: RestTemplate

Arjen Poutsma

In an earlier post, I blogged about the REST capabilities we added to Spring @MVC version 3.0. Later, Alef wrote about using the introduced functionality to add an Atom view to the Pet Clinic application. In this post, I would like to introduce the client-side capabilities we added in Milestone 2.

RestTemplate

The RestTemplate is the central Spring class for client-side HTTP access. Conceptually, it is very similar to the JdbcTemplate, JmsTemplate, and the various other templates found in the Spring Framework and other portfolio projects. This means, for instance, that the RestTemplate is thread-safe once constructed, and that you can use callbacks to customize its operations.

RestTemplate Methods

The main entry points of the template are named after the six main HTTP methods:

HTTP RestTemplate
DELETE delete(String, String...)
GET getForObject(String, Class, String...)
HEAD headForHeaders(String, String...)
OPTIONS optionsForAllow(String, String...)
POST postForLocation(String, Object, String...)
PUT put(String, Object, String...)

The names of these methods clearly indicate which HTTP method they invoke, while the second part of the name indicates what is returned. For instance, getForObject() will perform a GET, convert the HTTP response into an object type of your choice, and returns that object. postForLocation will do a POST, converting the given object into a HTTP request, and returns the response HTTP Location header where the newly created object can be found. As you can see, these methods try to enforce REST best practices.

URI Templates

Each of these methods takes a URI as first argument. That URI can be a URI template, and variables can be used to expand the template to a normal URI. The template variables can be passed in two forms: as a String variable arguments array, or as a Map. The string varargs variant expands the given template variables in order, so that

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

will perform a GET on http://example.com/hotels/42/bookings/21. The map variant expands the template based on variable name, and is therefore more useful when using many variables, or when a single variable is used multiple times. For example:

Map<String, String> vars = new HashMap<String, String>();
vars.put("hotel", "42");
vars.put("booking", "21");
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class, vars);

will also perform a GET on http://example.com/hotels/42/rooms/42.

HttpMessageConverters

Objects passed to and returned from the methods getForObject(), postForLocation(), and put() and are converted to HTTP requests and from HTTP responses by HttpMessageConverters. Converters for the main mime types and Java types are registered by default, but you can also write your own converter and plug it in the RestTemplate. In the example below, I will show you how that's done.

Using the RestTemplate to retrieve photos from Flickr

Rather than going through the various methods of the RestTemplate, I will show you how to use it for retrieving pictures from Flickr, Yahoo!s online photo-sharing application. This sample application searches Flickr for photos that match a given search term. It then shows these pictures using a simple Swing UI. To run the application yourself, you will need to create a Flickr account and apply for an API key.

Searching for photos

Flickr exposes various APIs to manipulate its vast library of photos. The flickr.photos.search method allows you to search for photos, by issuing a GET request on http://www.flickr.com/services/rest?method=flickr.photos.search&api+key=xxx&tags=penguins, where you enter your API key and the thing to search for (penguins in this case). As a result, you get back a XML document, describing the photos that conform to your query. Something like:

<photos page="2" pages="89" perpage="10" total="881">
	<photo id="2636" owner="47058503995@N01"
		secret="a123456" server="2" title="test_04"
		ispublic="1" isfriend="0" isfamily="0" />
	<photo id="2635" owner="47058503995@N01"
		secret="b123456" server="2" title="test_03"
		ispublic="0" isfriend="1" isfamily="1" />
	<photo id="2633" owner="47058503995@N01"
		secret="c123456" server="2" title="test_01"
		ispublic="1" isfriend="0" isfamily="0" />
	<photo id="2610" owner="12037949754@N01"
		secret="d123456" server="2" title="00_tall"
		ispublic="1" isfriend="0" isfamily="0" />
</photos>

Using the RestTemplate, retrieving such a document is quite trivial:

final String photoSearchUrl =
   "http://www.flickr.com/services/rest?method=flickr.photos.search&api+key={api-key}&tags={tag}&per_page=10";
Source photos = restTemplate.getForObject(photoSearchUrl, Source.class, apiKey, searchTerm);

where apiKey and searchTerm are two Strings given on the command line. This method uses the SourceHttpMessageConverter to convert the HTTP XML response into a javax.xml.transform.Source (Note that the SourceHttpMessageConverter was introduced shortly after we released Spring 3.0 M2, so you will have to get a recent snapshot (or the upcoming M3) to use it. The sample project available below is set up to retrieve these via Maven).

Retrieving the photos

Next, we're going to use an XPath expression to retrieve all the photo elements of the document. For this, we are going to use the XPathTemplate from Spring Web Services. We are going to execute the //photo expressions, returning all photo elements occurring anywhere in the document. The NodeMapper is a callback interface, whose mapNode() method will be invoked for each photo element in the document. In this case, we are retrieving the server, id, and secret attributes of this element, and use those to fill up a Map. Finally, we use the RestTemplate again, to retrieve the photo as a java.awt.image.BufferedImage. Thus when the XPath evaluation is done, the resulting imageList will contain an image for each photo in the XML document.

List<BufferedImage> imageList = xpathTemplate.evaluate("//photo", photos, new NodeMapper() {
    public Object mapNode(Node node, int i) throws DOMException {
        Element photo = (Element) node;

        Map<String, String> variables = new HashMap<String, String>(3);
        variables.put("server", photo.getAttribute("server"));
        variables.put("id", photo.getAttribute("id"));
        variables.put("secret", photo.getAttribute("secret"));

        String photoUrl = "http://static.flickr.com/{server}/{id}_{secret}_m.jpg";
        return restTemplate.getForObject(photoUrl, BufferedImage.class, variables);
    }
});

For instance, given the XML document given above, the imageList will contain 4 images. The URL for the first image retrieved will be http://static.flickr.com/2/2636_ a123456_m.jpg, the second is http://static.flickr.com/2/2635_ b123456_m.jpg, etc.

Converting the images

There is one more thing that needs to be done in order for the code to work: we will need to write a HttpMessageConverter that is able to read from the HTTP response, and create a BufferedImagefrom that. Doing so with the Java Image I/O API is fairly simple, we just need to implement the read() method defined in the HttpMessageConverter interface. Overall, our simple converter looks like this:

public class BufferedImageHttpMessageConverter implements HttpMessageConverter<BufferedImage> {

    public List<MediaType> getSupportedMediaTypes() {
        return Collections.singletonList(new MediaType("image", "jpeg"));
    }

    public boolean supports(Class<? extends BufferedImage> clazz) {
        return BufferedImage.class.equals(clazz);
    }

    public BufferedImage read(Class<BufferedImage> clazz, HttpInputMessage inputMessage) throws IOException {
        return ImageIO.read(inputMessage.getBody());
    }

    public void write(BufferedImage image, HttpOutputMessage message) throws IOException {
        throw new UnsupportedOperationException("Not implemented");
    }

}

Note that we didn't implement write() because we are not uploading images, just downloading them. Now we just have to plug this converter into the RestTemplate. We do that in the Spring application context:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="flickrClient" class="com.springsource.samples.resttemplate.FlickrClient">
        <constructor-arg ref="restTemplate"/>
        <constructor-arg ref="xpathTemplate"/>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
                <bean class="com.springsource.samples.resttemplate.BufferedImageHttpMessageConverter"/>
            </list>
        </property>
    </bean>

    <bean id="xpathTemplate" class="org.springframework.xml.xpath.Jaxp13XPathTemplate"/>

</beans>

Showing the photos

The final stage is to show the photos in a simple GUI. For this, we use Swing:

JFrame frame = new JFrame(searchTerm + " photos");
frame.setLayout(new GridLayout(2, imageList.size() / 2));
for (BufferedImage image : imageList) {
    frame.add(new JLabel(new ImageIcon(image)));
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);

which gives us the following:

Penguins

Overall, I hope this post showed you how simple it can be to use the RestTemplate to interact with HTTP servers. In just under 30 lines of Java code, we created a GUI that shows pictures of everybody's favorite bird: the penguin! Check out the RestTemplate and let us know what you think!

Downloads

A Maven project containing the code above can be downloaded here. Note that the project is based on a nightly snapshot build of Spring. The upcoming Milestone 3 of Spring will contain the necessary classes as well.

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • TwitThis
 

29 responses


  1. Great blog Arjen. You did forget to mention how to run the app so I thought I'd save some of you a bit of Googling:

    mvn exec:java -Dexec.mainClass="com.springsource.samples.resttemplate.Driver" -Dexec.args="[your key here] penguin"

    -Thomas


  2. Looks great, but I would like all my client side HTTP handling to be (ultimately) done by Apache's HttpClient 4.0… Can I make RestTemplate call into Apaches HttpClient 4.0?


  3. @Morton

    You can plug in Commons Http Client 3 into the template currently, since version 4 is still in beta. As soon as 4 is out, we might add support for it.


  4. This is an excellent client-side complement to the MVC framework REST extensions, love the XPathTemplate/NodeMapper!


  5. Hi Arjen,

    How do we do authentication with RestTemplate ?


  6. @ Abdullah

    You can plug in a Commons HTTP client into the constructor, and set authentication on that, see here and and here.


  7. Hi Arjen,

    is there support for the OXM mapper in RestTemplate. I'd like to have something like

    MyDomainObject foo = restTemplate.getForObject("http://server/foos/{id}", MyDomainObject.class, "42");

    On the server I would have a marshaller configured to convert instances of MyDomainObject. How do I connect the marshaller with the template?

    Thanks Harald


  8. @Harald

    You can use a marshaller through the MarshallingHttpMessageConverter. This class didn't make it to M2 yet, so you will need to use a snapshot, or wait till M3.


  9. Hi Arjen,

    I am working on openCRX, which have Rest Services, one of them is creating a Contact.

    For Contact service, using Apache HttpClient, I am using the below code:

    String url = "http://localhost:8080/opencrx-rest-CRX/org.opencrx.kernel.account1/provider/CRX/segment/Standard/account";

    HttpClient client = new HttpClient();

    PostMethod method = new PostMethod(request);

    String contact = ""
    ""
    "mr"
    "abdullah"
    "shaikh"
    "";

    method.setRequestBody(contact);

    client.executeMethod(method);

    But how should I do it using Spring's RestTemplate ?

    I tried using the code below for RestTemplate:

    HttpClient httpClient = new HttpClient();

    ClientHttpRequestFactory requestFactory = new CommonsClientHttpRequestFactory(httpClient);

    RestTemplate template = new RestTemplate(requestFactory);

    String url = "http://localhost:8080/opencrx-rest-CRX/org.opencrx.kernel.account1/provider/CRX/segment/Standard/account";

    Map vars = new HashMap();

    vars.put("salutation", "mr");
    vars.put("firstName", "test2");
    vars.put("middleName", "test2");
    vars.put("lastName", "test2");
    vars.put("jobTitle", "test2");

    URI uri = template.postForLocation(url, null, vars);

    Thanks,
    Abdullah


  10. The xml tags in contact variable got replace, the root tag is org.opencrx.kernel.account1.Contact>


  11. hey I got it .. I guess I need to write http message converters and the code should be ..

    Contact contact = new Contact();
    contact.setFirstName("test2");
    contact.setLastName("test2");

    URI uri = template.postForLocation(url, contact);


  12. Hi Arjen,

    Are there some similar server side capabilities in Spring 3.0? We are using Spring 2.x for our upcoming site. When can we expect a final production ready Spring 3.0?

    thanks in advance..


  13. I got my first answer from http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/
    can you please tell me when can we expect a final production ready Spring 3.0?


  14. @Abdullah

    There are a couple of XML converters available for handling XML. One of which is the MarshallingHttpMessageConverter, which can deal with JAXB2, Castor, XMLBeans, JiBX and XStream. The other option is to use the SourceHttpMessageConverter, which can deal with javax.xml.transform.Source objects, or more specifically DOMSource, StreamSource, and SAXSource.


  15. Are you able to post the slides for you presentation at the spring one europe convention?


  16. @Chris

    I believe they will be available at the the SpringOne site soon.


  17. Hi,

    I've been using RestTemplate for a few weeks now. One thing I don't understand is why there is no method for a POST that returns a Response object, with a default Callback and Extractor?

    The only way to execute a POST and process the response is to use execute() providing custom Callback and Extractor classes, which seems to be very elaborate.


  18. @Graham

    I kept the interface as simple as possible for the initial release, knowing that we would probably need to add more methods later, via user requests (like yourself :) .

    So feel free to create a JIRA issue, and I will add such a postForObject() method.


  19. Hi Arjen,

    We have a requirement to upload documents (Word, pdf, etc). The Request is expected to be a multipart/mixed MIME type, with the first section containing the Xml defining the document, and the second section containing the actual document.

    Is there a way to create multipart requests using RestTemplate?

    thanks,
    Graham


  20. Hi Arjen
    Your post on April 1st, 2009 at 9:20 am

    @ Abdullah

    You can plug in a Commons HTTP client into the constructor, and set authentication on that, see here and and here.

    Can you please send out the snippet for this implement, to get the authentication like SSL. Currently I got the handshake error when trying to do a GET to the https: site.
    Thanks

    Fray


  21. Hi Arjen,

    This is great stuff, the code is well-written, thanks for your work on it. I'd like to expand the code to be able to work with OAuth. I've done this integration already with Restlets, but needed to make some changes, and figured I'd put the effort towards an active code base instead.

    The only real effort that needs to be put into this is the ordering of the parameters and signing them. This seems to be something that could be managed by UriTemplate, but as the code is currently, it is statically instantiated inside RestTemplate.

    I'm in the process of developing this code and am interested in contributing it. Does it sound like something you would be interested in?

    Cheers, Brian


  22. @Brian,

    Thanks!

    Contributions are always welcome. Feel free to create a JIRA issue on http://jira.springframework.org/browse/SPR, and attach the code to that.

    Note, however, that we are quite close to releasing 3.0 RC1, so your code will probably not make it into 3.0 as we are stabilizing.


  23. Hi Arjen, thanks for your response. No problem on the timing, there's always another version and this code is isolated enough that I can run my own version until it's integrated.

    A crash course on OAuth would be to say that the hierarchical part of the URI is left alone for signature purposes, but all the query attributes need to be sorted and a URL string generated before the hash is calculated. As well, in a form-based POST, the attributes of the form need to be included in that sort for the signature calculation.

    Two approaches come to mind: The first would be to rewrite UriTemplate such that it can add a signature in-place as a part of the variable expansion. This is complicated by the fact that the sort for the signature also requires any form variables that may exist plus the method (GET, POST, etc.) to calculate the hash. In this case, it probably makes sense to refactor the UriTemplate.expand() code to a client responsibility, sending in a final java.net.URI. This has the least impact to the existing code.

    The second approach would be to add authorization post-processing code to doExecute(). But in doing so, there is an efficiency cost since the query part of the URI needs to be re-parsed so it can be sorted. The advantage here is by the time the code is executed, we have all the form components and completed URI available to us, and in doing so, the existing functionality exposed to the client and managed by UriTemplate is unchanged.

    WDYT? Feel free to respond off-list to my email address.


  24. Oh, my bad, the third and possibly best option is creating a RequestCallback. It will be computationally the most expensive, but with the least (or no) impact to the current code. That way, you can have a stab at it and merge it into the code base as you are most comfortable with for long-term support.


  25. Great work for 3.0!

    Unfortunately, the maven 3.0.0.* .pom files have weird dependencies configured such as:
    org.apache.commons
    com.springsource.org.apache.commons.logging
    or
    org.apache.log4j
    com.springsource.org.apache.log4j
    and many others…

    It looks like the artifcatId is worng on all the external dependencies.

    Am I missing something?

    P.S.: I am using the milestone repo

    SpringSource Enterprise Bundle Repositorys
    http://repository.springsource.com/maven/bundles/milestone


  26. Hi ,

    The above is very helpful.

    I have a rest server in apache cxf with spring. I was looking for the list capture through rest template. I found the following code snippet is working well. Hopefully It would help others

    SecurityCredentialBean[] res =(SecurityCredentialBean[])this.restTemplate.getForObject(uri, SecurityCredentialBean[].class, vars);
    List securityCredentialBeans = Arrays.asList(res);

    Thanks
    –Siddhartha


  27. I tried to compile a project that you provided as an example but it did not compile (interface had unimplemented methods). So I corrected it and added maven-dependency-plugin to gather all dependencies and copy to one place (i.e. target/lib) so the start of a java process will be as smooth as possible.

    zip uploaded on filefactory:
    http://www.filefactory.com/file/a127bhd/n/spring3-resttemplate-20091220.zip
    link on the bottom of the page ;)


  28. I corrected the file for downloading and added maven-dependency-plugin for easier java process launching.


  29. I was looking at http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#RestTemplate() and wondering why the "default settings" are not documented. I know I can look in the source code to see which implementation is currently used, but am concerned since it isn't documented that it might change?? Is there any reason not to specify a concrete ClientHttpRequestFactory implmentation as default in the Javadocs?

6 trackbacks

Leave a Reply