spring-framework/spring-framework-reference/src/rest.xml

971 lines
45 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="rest">
<title>REST support</title>
<section id="rest-introduction">
<title>Introduction</title>
<para>The goal of Spring's REST support is to make the development of
RESTful Web services and applications easier.</para>
<para>Client-side access to RESTful resources is greatly simplified using
Spring <classname>RestTemplate</classname>.
<classname>RestTemplate</classname> follows in the footsteps of other
template classes in Spring such as <classname>JdbcTemplate</classname> and
<classname>JmsTemplate</classname>. Instead of dealing with a verbose
lower level API such as Apache Commons <classname>HttpClient</classname>
to create RESTful request, RestTemplate provides one liner methods that
are purpose built for RESTful programming.</para>
<para>On the server-side, Spring's REST support is based upon Spring's
existing annotation based MVC framework. (For those interested in the
rational for that decision, and for not implementing JAX-RS, read Arjen
Poutsma's SpringSource TeamBlog <ulink
url="http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/">entry</ulink>.)
With little effort, you can marshall data out of a RESTful request using
<classname>@RequestMapping</classname> and
<classname>@PathVariable</classname> annotations and return different
views as determined by the request's <literal>Context-Type</literal>
header.</para>
<para>In this chapter we describe all the features of Spring's REST
support. It is divided into two main chapters, one for the server-side and
one for the client-side. For those new to Spring's <link linkend="mvc">MVC
framework</link>, you may want to read through the reference documentation
on <link linkend="mvc-annotation">annotation-based controller
configuration</link> to understand the general programming model.</para>
</section>
<section id="rest-creating-services">
<title>Creating RESTful services</title>
<para>Spring's annotation-based MVC framework serves as the basis for
creating RESTful Web Services. As such, you configure your servlet
container as you would for a Spring MVC application using Spring's <link
linkend="mvc-servlet">DispatcherServlet</link>.</para>
<section id="rest-uritemplate">
<title>URI Templates</title>
<para>RESTful services use URIs to name resources. To facilitate
accessing the information contained in a URI, its structure follows
conventions so that it can easily be described in a parameterized form.
The <ulink url="http://bitworking.org/projects/URI-Templates/">proposed
RFC</ulink> for URI Templates defines how an URI is parameterized. For
example, the URI Template</para>
<programlisting>http://www.example.com/users/{userid}</programlisting>
<para>contains the variable 'userid'. If we assign the variable the
value "fred", then 'expanding' the URI Template gives.</para>
<programlisting>http://www.example.com/users/fred</programlisting>
<para>When processing a request the URI can be compared to an expected
URI Template in order to extract a collection of variables.</para>
<para>Spring uses the <classname>@RequestMapping</classname> method
annotation to define the URI Template for the request. The
<classname>@PathVariable</classname> annotation is used to extract the
value of the template variables and assign their value to a method
variable. A Spring controller method to process above example is shown
below;</para>
<programlisting language="java">@RequestMapping(value="/users/{userId}", method=RequestMethod.GET)
public String getUser(@PathVariable String userId) {
// implementation omitted...
}</programlisting>
<para>The request <literal>http://www.example.com/users/fred</literal>
will bind the userId method parameter to the String value 'fred'.</para>
<section id="rest-path-variable">
<title>Mapping RESTful URLs with the @PathVariable annotation</title>
<para>The <classname>@PathVariable</classname> method parameter
annotation is used to indicate that a method parameter should be bound
to the value of a URI template variable.</para>
<para>The following code snippet shows the use of a single
<classname>@PathVariable</classname> in a controller method:</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(<emphasis role="bold">@PathVariable</emphasis> String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}
</programlisting>
<para>The URI Template "<literal>/owners/{ownerId}</literal>"
specifies the variable name ownerId. When the controller handles this
request, the value of ownerId is set the value in the request URI. For
example, when a request comes in for /owners/fred, the value 'fred' is
bound to the method parameter <literal>String
ownerId</literal>.</para>
<para>The matching of method parameter names to URI Template variable
names can only be done if your code is compiled with debugging
enabled. If you do have not debugging enabled, you must specify the
name of the URI Template variable name to bind to in the @PathVariable
annotation. For example</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(<emphasis role="bold">@PathVariable</emphasis>("ownerId") String ownerId, Model model) {
// implementation omitted
}
</programlisting>
<para>The name of the method parameter does not matter in this case,
so you may also use a controller method with the signature shown
below</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(<emphasis role="bold">@PathVariable</emphasis>("ownerId") String theOwner, Model model) {
// implementation omitted
}</programlisting>
<para>Multiple @PathVariable annotations can be used to bind to
multiple URI Template variables as shown below:</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)
public String findPet(<emphasis role="bold">@PathVariable</emphasis> String ownerId, <emphasis
role="bold">@PathVariable</emphasis> String petId, Model model) {
Owner owner = ownerService.findOwner(ownderId);
Pet pet = owner.getPet(petId);
model.addAttribute("pet", pet);
return "displayPet";
}
</programlisting>
<para>The following code snippet shows the use of path variables on a
relative path</para>
<programlisting language="java">@Controller
@RequestMapping(<emphasis role="bold">"/owners/{ownerId}/**"</emphasis>)
public class RelativePathUriTemplateController {
@RequestMapping(<emphasis role="bold">"/pets/{petId}"</emphasis>)
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
</programlisting>
<tip>
<para>method parameters that are decorated with the
<interfacename>@PathVariable</interfacename> annotation can be of
<emphasis role="bold">any simple type </emphasis>such as int, long,
Date... Spring automatically converts to the appropriate type and
throws a <classname>TypeMismatchException</classname> if the type is
not correct.</para>
</tip>
</section>
<section>
<title>Mapping the request body with the @RequestBody
annotation</title>
<para>The <classname>@RequestBody</classname> method parameter
annotation is used to indicate that a method parameter should be bound
to the value of the HTTP request body. For example,</para>
<programlisting language="java">@RequestMapping(value = "/something", method = RequestMethod.PUT)
public void handle(@RequestBody String body, Writer writer) throws IOException {
writer.write(body);
}</programlisting>
<para>The conversion of the request body to the method argument is
done using a <interfacename>HttpMessageConverter</interfacename>.
<interfacename>HttpMessageConverter</interfacename> is responsible for
converting from the HTTP request message to an object and converting
from an object to the HTTP response body.
<classname>DispatcherServlet</classname> supports annotation based
processing using the
<classname>DefaultAnnotationHandlerMapping</classname> and
<classname>AnnotationMethodHandlerAdapter</classname>. In Spring 3 the
<classname>AnnotationMethodHandlerAdapter</classname> has been
extended to support the <classname>@RequestBody</classname> and has
several <interfacename>HttpMessageConverters</interfacename>
registered by default, these are</para>
<itemizedlist>
<listitem>
<para><classname>ByteArrayHttpMessageConverter</classname> -
converts byte arrays</para>
</listitem>
<listitem>
<para><classname>StringHttpMessageConverter</classname> - converts
strings</para>
</listitem>
<listitem>
<para><classname>FormHttpMessageConverter</classname> - converts
form data to/from a MultiValueMap&lt;String, String&gt;</para>
</listitem>
<listitem>
<para><classname>SourceHttpMessageConverter</classname> - converts
to/from a javax.xml.transform.Source;</para>
</listitem>
<listitem>
<para><classname>MarshallingHttpMessageConverter</classname> -
converts to/from an object using the
<classname>org.springframework.oxm</classname> package.</para>
</listitem>
</itemizedlist>
<para>More information on these converters can be found in the section
<link linkend="rest-message-conversion">Message
Converters</link>.</para>
<para>The <classname>MarshallingHttpMessageConverter</classname>
requires a <interfacename>Marshaller</interfacename> and
<interfacename>Unmarshaller</interfacename> from the
<classname>org.springframework.oxm</classname> package to be
configured on an instance of
<classname>AnnotationMethodHandlerAdapter</classname> in the
application context. For example</para>
<programlisting language="xml">&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt;
&lt;property name="messageConverters"&gt;
&lt;util:list id="beanList"&gt;
&lt;ref bean="stringHttpMessageConverter"/&gt;
&lt;ref bean="marshallingHttpMessageConverter"/&gt;
&lt;/util:list&gt;
&lt;/property
&lt;/bean&gt;
&lt;bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter"/&gt;
&lt;bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"&gt;
&lt;property name="marshaller" ref="castorMarshaller" /&gt;
&lt;property name="unmarshaller" ref="castorMarshaller" /&gt;
&lt;/bean&gt;
&lt;bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/&gt;
</programlisting>
</section>
</section>
<section id="rest-multiple-representations">
<title>Returning multiple representations</title>
<para>A RESTful architecture may expose multiple representations of a
resource. There are two strategies for a client to inform the server of
the representation it is interested in receiving.</para>
<para>The first strategy is to use a distinct URI for each resource.
This is typically done by using a different file extension in the URI.
For example the URI<literal>
http://www.example.com/users/fred.pdf</literal> requests a PDF
representation of the user fred while
<literal>http://www.example.com/users/fred.xml</literal> requests an XML
representation.</para>
<para>The second strategy is for the client to use the same URI to
locate the resource but set the <literal>Accept</literal> HTTP request
header to list the <ulink
url="http://en.wikipedia.org/wiki/Internet_media_type">media
types</ulink> that it understands. For example, a HTTP request for
<literal>http://www.example.com/users/fred</literal> with an
<literal>Accept</literal> header set to <literal>application/pdf
</literal>requests a PDF representation of the user fred while
<literal>http://www.example.com/users/fred</literal> with an
<literal>Accept</literal> header set to <literal>text/xml</literal>
requests an XML representation. This strategy is known as <ulink
url="http://en.wikipedia.org/wiki/Content_negotiation">content
negotiation</ulink>.</para>
<note>
<para>One issue with the Accept header is that is impossible to change
it in a web browser, in HTML. For instance, in Firefox, it's fixed
to</para>
<programlisting>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
</programlisting>
<para>For this reason it is common to see the use of a distinct URI
for each representation.</para>
</note>
<para>To support multiple representations of a resource Spring provides
the <classname>ContentNegotiatingViewResolver</classname> to resolve a
view based on the file extension or <literal>Accept</literal> header of
the HTTP request. <classname>ContentNegotiatingViewResolver</classname>
does not perform the view resolution itself, but instead delegates to a
list of view resolvers set using the bean property
<literal>ViewResolvers</literal>.</para>
<para>The <classname>ContentNegotiatingViewResolver</classname> selects
an appropriate <classname>View</classname> to handle the request by
comparing the request media type(s) with the media type (a.k.a.
<literal>Content-Type</literal>) supported by the
<classname>View</classname> associated with each of its
<classname>ViewResolvers</classname>. The first
<classname>View</classname> in the list that has a compatible
<literal>Content-Type</literal> is used to return the representation to
the client. The <literal>Accept</literal> header may include wild cards,
for example 'text/*', in which case a <classname>View</classname> whose
Context-Type was 'text/xml' is a compatible match.</para>
<para>To support the resolution of a view based on a file extension,
<classname>ContentNegotiatingViewResolver</classname>'s bean property
<literal>MediaTypes</literal> is used to specify a mapping of file
extensions to media types. For more information on the algorithm to
determine the request media type, refer to the API documentation for
<classname>ContentNegotiatingViewResolver</classname>..</para>
<para>Here is an example configuration of a
<classname>ContentNegotiatingViewResolver</classname></para>
<programlisting language="xml"> &lt;bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"&gt;
&lt;property name="mediaTypes"&gt;
&lt;map&gt;
&lt;entry key="atom" value="application/atom+xml"/&gt;
&lt;entry key="html" value="text/html"/&gt;
&lt;/map&gt;
&lt;/property&gt;
&lt;property name="viewResolvers"&gt;
&lt;list&gt;
&lt;bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/&gt;
&lt;bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
&lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
&lt;property name="suffix" value=".jsp"/&gt;
&lt;/bean&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="content" class="com.springsource.samples.rest.SampleContentAtomView"/&gt;</programlisting>
<para>The <classname>InternalResourceViewResolver</classname> handles
the translation of view names and JSP pages while the
<classname>BeanNameViewResolver</classname> returns a view based on the
name of a bean. (See "<link
linkend="mvc-viewresolver-resolver">Resolving views - the ViewResolver
interface</link>" for more details on how Spring looks up and
instantiates a view.) In this example, the <literal>content</literal>
bean is a class that inherits from
<classname>AbstractAtomFeedView</classname> which returns an Atom RSS
feed. For more information on creating an Atom Feed representation see
the section 'Atom Views'.</para>
<para>In this configuration, if a request is made with a .html extension
the view resolver will look for a view that matches the text/html media
type. The <classname>InternalResourceViewResolver</classname> provides
the matching view for text/html. If the request is made with the file
extension .atom, the view resolver will look for a view that matches the
application/atom+xml media type. This view is provided by the
<classname>BeanNameViewResolver</classname> that maps to the
<classname>SampleContentAtomView</classname> if the view name returned
is 'content'. Alternatively, client requests could be made without a
file extension and setting the Accept header to the preferred media-type
and the same resolution of request to views would occur.</para>
<note>
<para>If <classname>ContentNegotiatingViewResolver</classname>'s list
of ViewResolvers is not configured explicitly, then it will
automatically use any ViewResolvers defined in the application
context.</para>
</note>
<para>The corresponding controller code that returns an Atom RSS feed
for a URI of the form <literal>http://localhost/content.atom</literal>
or <literal>http://localhost/content</literal> with an
<literal>Accept</literal> header of application/atom+xml is shown
below</para>
<programlisting language="java">@Controller
public class ContentController {
private List&lt;SampleContent&gt; contentList = new ArrayList&lt;SampleContent&gt;();
@RequestMapping(value="/content", method=RequestMethod.GET)
public ModelAndView getContent() {
ModelAndView mav = new ModelAndView();
mav.setViewName("content");
mav.addObject("sampleContentList", contentList);
return mav;
}
}</programlisting>
<para></para>
</section>
<section id="rest-views">
<title>Views</title>
<para>Several views were added in Spring 3 to help support creating
RESTful services. They are:</para>
<itemizedlist>
<listitem>
<para><classname>AbstractAtomFeedView</classname> - returns an Atom
feed</para>
</listitem>
<listitem>
<para><classname>AbstractRssFeedView</classname> - returns a RSS
feed</para>
</listitem>
<listitem>
<para><classname>MarshallingView</classname> - returns an XML
representation using Spring's Object to XML mapping (OXM)
functionality</para>
</listitem>
</itemizedlist>
<note>
<para>Available separately is the
<classname>JacksonJsonView</classname> included as part of the Spring
JavaScript project.</para>
</note>
<section id="rest-feedview">
<title>Feed Views</title>
<para>Both <classname>AbstractAtomFeedView</classname> and
<classname>AbstractRssFeedView</classname> inherit from the base class
<classname>AbstractFeedView</classname> and are used to provide Atom
and RSS Feed views respectfully. They are based on java.net's <ulink
url="https://rome.dev.java.net">ROME</ulink> project and are located
in the package
<literal>org.springframework.web.servlet.view.feed</literal>.</para>
<para><classname>AbstractAtomFeedView</classname> requires you to
implement the <methodname>buildFeedEntries</methodname> method and
optionally override the <methodname>buildFeedMetadata</methodname>
method (the default implementation is empty), as shown below</para>
<programlisting language="java">public class SampleContentAtomView extends AbstractAtomFeedView {
@Override
protected void buildFeedMetadata(Map&lt;String, Object&gt; model, Feed feed,
HttpServletRequest request) {
// implementation omitted
}
@Override
protected List&lt;Entry&gt; buildFeedEntries(Map&lt;String, Object&gt; model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
// implementation omitted
}
}</programlisting>
<para>Similar requirements apply for implementing
<classname>AbstractRssFeedView</classname>, as shown below</para>
<programlisting language="java">public class SampleContentAtomView extends AbstractRssFeedView {
@Override
protected void buildFeedMetadata(Map&lt;String, Object&gt; model, Channel feed,
HttpServletRequest request) {
// implementation omitted
}
@Override
protected List&lt;Item&gt; buildFeedItems(Map&lt;String, Object&gt; model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
// implementation omitted
}
}</programlisting>
<para>The <methodname>buildFeedItems</methodname> and
<methodname>buildFeedEntires</methodname> pass in the HTTP request in
case you need to access the Locale. The HTTP response is passed in
only for the setting of cookies or other HTTP headers. The feed will
automatically be written to the response object after the method
returns.</para>
<para>For an example of creating a Atom view please refer to Alef
Arendsen's SpringSource TeamBlog <ulink
url="http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/">entry</ulink>.</para>
</section>
<section>
<title>XML Marshalling View</title>
<para>The <classname>MarhsallingView</classname> uses a XML
<interfacename>Marshaller</interfacename> defined in the
<classname>org.springframework.oxm</classname> package to render the
response content as XML. The object to be marshalled can be set
explicitly using <classname>MarhsallingView</classname>'s
<property>modelKey</property> bean property. Alternatively, the view
will iterate over all model properties marhsall only those types that
are supported by the <interfacename>Marshaller</interfacename>. For
more information on the functionality in the
<classname>org.springframework.oxm</classname> package refer to the
chapter <link linkend="oxm">Marshalling XML using O/X
Mappers</link>.</para>
</section>
</section>
<section id="rest-method-conversion">
<title>HTTP Method Conversion</title>
<para>A key principle of REST is the use of the Uniform Interface. This
means that all resources (URLs) can be manipulated using the same four
HTTP methods: GET, PUT, POST, and DELETE. For each methods, the HTTP
specification defines the exact semantics. For instance, a GET should
always be a safe operation, meaning that is has no side effects, and a
PUT or DELETE should be idempotent, meaning that you can repeat these
operations over and over again, but the end result should be the same.
While HTTP defines these four methods, HTML only supports two: GET and
POST. Fortunately, there are two possible workarounds: you can either
use JavaScript to do your PUT or DELETE, or simply do a POST with the
'real' method as an additional parameter (modeled as a hidden input
field in an HTML form). This latter trick is what Spring's
<classname>HiddenHttpMethodFilter</classname> does. This filter is a
plain Servlet Filter and therefore it can be used in combination with
any web framework (not just Spring MVC). Simply add this filter to your
web.xml, and a POST with a hidden _method parameter will be converted
into the corresponding HTTP method request.</para>
<section id="rest-form-tags">
<title>Supporting Spring form tags</title>
<para>To support HTTP method conversion the Spring MVC form tag was
updated to support setting the HTTP method. For example, the following
snippet taken from the updated Petclinic sample</para>
<programlisting language="xml">&lt;form:form method="delete"&gt;
&lt;p class="submit"&gt;&lt;input type="submit" value="Delete Pet"/&gt;&lt;/p&gt;
&lt;/form:form&gt;</programlisting>
<para>This will actually perform an HTTP POST, with the 'real' DELETE
method hidden behind a request parameter, to be picked up by the
<classname>HiddenHttpMethodFilter</classname>. The corresponding
@Controller method is shown below</para>
<programlisting language="java">@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
this.clinic.deletePet(petId);
return "redirect:/owners/" + ownerId;
}</programlisting>
</section>
</section>
<section id="rest-etag">
<title>ETag support</title>
<para>An <ulink
url="http://en.wikipedia.org/wiki/HTTP_ETag">ETag</ulink> (entity tag)
is an HTTP response header returned by an HTTP/1.1 compliant web server
used to determine change in content at a given URL. It can be considered
to be the more sophisticated successor to the
<literal>Last-Modified</literal> header. When a server returns a
representation with an ETag header, the client can use this header in
subsequent GETs, in an <literal>If-None-Match</literal> header. If the
content has not changed, the server will return <literal>304: Not
Modified</literal>.</para>
<para>Support for ETags is provided by the servlet filter
<classname>ShallowEtagHeaderFilter</classname>. Since it is a plain
Servlet Filter, and thus can be used in combination with any web
framework. The <classname>ShallowEtagHeaderFilter</classname> filter
creates so-called shallow ETags (as opposed to deep ETags, more about
that later). The way it works is quite simple: the filter simply caches
the content of the rendered JSP (or other content), generates an MD5
hash over that, and returns that as an ETag header in the response. The
next time a client sends a request for the same resource, it uses that
hash as the <literal>If-None-Match</literal> value. The filter notices
this, renders the view again, and compares the two hashes. If they are
equal, a <literal>304</literal> is returned. It is important to note
that this filter will not save processing power, as the view is still
rendered. The only thing it saves is bandwidth, as the rendered response
is not sent back over the wire.</para>
<para>Deep ETags are a bit more complicated. In this case, the ETag is
based on the underlying domain objects, RDMBS tables, etc. Using this
approach, no content is generated unless the underlying data has
changed. Unfortunately, implementing this approach in a generic way is
much more difficult than shallow ETags. Spring may provide support for
deep ETags in a later release by relying on JPA's @Version annotation,
or an AspectJ aspect.</para>
</section>
<section id="rest-exception">
<title>Exception Handling</title>
<para>The <classname>@ExceptionHandler</classname> method annotation is
used within a controller to specify which method will be invoked when an
exception of a specific type is thrown during the execution of
controller methods. For example</para>
<programlisting language="java">@Controller
public class SimpleController {
// other controller method omitted
@ExceptionHandler(IOException.class)
public String handleIOException(IOException ex, HttpServletRequest request) {
return ClassUtils.getShortName(ex.getClass());
}
}</programlisting>
<para>will invoke the 'handlerIOException' method when a
<classname>java.io.IOException</classname> is thrown.</para>
<para>The <classname>@ExceptionHandler</classname> value can be set to
an array of Exception types. If an exception is thrown matches one of
the types in the list, then the method annotated with the matching
<classname>@ExceptionHandler</classname> will be invoked. If the
annotation value is not set then the exception types listed as method
arguments are used.</para>
<para>Much like standard controller methods annotated with a
<classname>@RequestMapping</classname> annotation, the method arguments
and return values of <classname>@ExceptionHandler</classname> methods
are very flexible. For example, the
<classname>HttpServletRequest</classname> can be accessed in Servlet
environments and the <classname>PortletRequest</classname> in Portlet
environments. The return type can be a <classname>String</classname>,
which is interpreted as a view name or a
<classname>ModelAndView</classname> object. Please refer to the API
documentation for more details.</para>
</section>
</section>
<section id="rest-client-access">
<title>Accessing RESTful services on the Client</title>
<para>The <classname>RestTemplate</classname> is the core class for
client-side access to RESTful services. It is conceptually similar to
other template classes in Spring, such as
<classname>JdbcTemplate</classname> and <classname>JmsTemplate</classname>
and other template classes found in other Spring portfolio projects.
<classname>RestTemplate</classname>'s behavior is customized by providing
callback methods and configuring the
<interfacename>HttpMessageConverter</interfacename> used to marshal
objects into the HTTP request body and to unmarshall any response back
into an object. As it is common to use XML as a message format, Spring
provides a <classname>MarshallingHttpMessageConverter</classname> that
uses the Object-to-XML framework that is part of the
<classname>org.springframework.oxm</classname> package. This gives you a
wide range of choices of XML to Object mapping technologies to choose
from.</para>
<para>This section describes how to use the
<classname>RestTemplate</classname> and its associated
<interfacename>HttpMessageConverters</interfacename>.</para>
<section id="rest-resttemplate">
<title>RestTemplate</title>
<para>Invoking RESTful services in Java is typically done using a helper
class such as Jakarta Commons <classname>HttpClient</classname>. For
common REST operations this approach is too low level as shown
below.</para>
<programlisting>String uri = "http://example.com/hotels/1/bookings";
PostMethod post = new PostMethod(uri);
String request = // create booking request content
post.setRequestEntity(new StringRequestEntity(request));
httpClient.executeMethod(post);
if (HttpStatus.SC_CREATED == post.getStatusCode()) {
Header location = post.getRequestHeader("Location");
if (location != null) {
System.out.println("Created new booking at :" + location.getValue());
}
}</programlisting>
<para>RestTemplate provides higher level methods that correspond to each
of the six main HTTP methods that make invoking many RESTful services a
one-liner and enforce REST best practices.</para>
<table>
<title>Overview of RestTemplate methods</title>
<tgroup cols="2">
<tbody>
<row>
<entry><emphasis role="bold">HTTP Method</emphasis></entry>
<entry><emphasis role="bold">RestTemplate
Method</emphasis></entry>
</row>
<row>
<entry>DELETE</entry>
<entry><ulink
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#delete(String,%20String...)">delete(String
url, String… urlVariables)</ulink></entry>
</row>
<row>
<entry>GET</entry>
<entry><ulink
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject(String,%20Class,%20String...)">getForObject(String
url, Class&lt;T&gt; responseType, String…
urlVariables)</ulink></entry>
</row>
<row>
<entry>HEAD</entry>
<entry><ulink
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#headForHeaders(String,%20String...)">headForHeaders(String
url, String… urlVariables)</ulink></entry>
</row>
<row>
<entry>OPTIONS</entry>
<entry><ulink
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#optionsForAllow(String,%20String...)">optionsForAllow(String
url, String… urlVariables)</ulink></entry>
</row>
<row>
<entry>POST</entry>
<entry><ulink
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#postForLocation(String,%20Object,%20String...)">postForLocation(String
url, Object request, String… urlVariables)</ulink></entry>
</row>
<row>
<entry>PUT</entry>
<entry><ulink
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#put(String,%20Object,%20String...)">put(String
url, Object request, String…urlVariables)</ulink></entry>
</row>
</tbody>
</tgroup>
</table>
<para>The names of <classname>RestTemplate</classname> methods follow a
naming convention, the first part indicates what HTTP method is being
invoked and the second part indicates what is returned. For example, the
method <methodname>getForObject</methodname> will perform a GET, convert
the HTTP response into an object type of your choice and return that
object. The method <methodname>postForLocation</methodname> will do a
POST, converting the given object into a HTTP request and return the
response HTTP Location header where the newly created object can be
found In case of an exception processing the HTTP request, an exception
of the type <classname>RestClientException</classname> will be
thrown.</para>
<para>Objects passed to and returned from these methods are converted to
and from HTTP messages by
<interfacename>HttpMessageConverter</interfacename> instances.
Converters for the main mime types are registered by default, but you
can also write your own converter and register it via the
<methodname>messageConverters</methodname> bean property. The default
converter instances registered with the template are
<classname>ByteArrayHttpMessageConverter</classname>,
<classname>StringHttpMessageConverter</classname>,
<classname>FormHttpMessageConverter</classname> and
<classname>SourceHttpMessageConverter</classname>. You can override
these defaults using the <methodname>messageConverters</methodname> bean
property as would be required if using the
<classname>MarshallingHttpMessageConverter</classname>.</para>
<para>Each method takes URI template arguments in two forms, either as a
<literal>String</literal> variable length argument or a
<literal>Map&lt;String,String&gt;</literal>. For example,</para>
<programlisting language="java">String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}",
String.class,"42", "21");
</programlisting>
<para>using variable length arguments and</para>
<programlisting language="java">Map&lt;String, String&gt; vars = Collections.singletonMap("hotel", "42");
String result =
restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
</programlisting>
<para>using a <literal>Map&lt;String,String&gt;</literal>.</para>
<para>To create an instance of <classname>RestTemplate</classname> you
can simply call the default constructor. This will use standard Java
classes from the <literal>java.net</literal> package as the underlying
implementation to create HTTP requests. This can be overridden by
specifying an implementation of
<interfacename>ClientHttpRequestFactory</interfacename>. Spring provides
the implementation
<classname>CommonsClientHttpRequestFactory</classname> that uses the
Jakarta Commons <classname>HttpClient</classname> to create requests.
<classname>CommonsClientHttpRequestFactory</classname> is configured
using an instance of
<classname>org.apache.commons.httpclient.HttpClient</classname> which
can in turn be configured with credentials information or connection
pooling functionality.</para>
<para>The previous example using Jakarta Commons
<classname>HttpClient</classname> directly rewritten to use the
<classname>RestTemplate</classname> is shown below</para>
<programlisting>uri = "http://example.com/hotels/{id}/bookings";
RestTemplate template = new RestTemplate();
Booking booking = // create booking object
URI location = template.postForLocation(uri, booking, "1");
</programlisting>
<para>The general callback interface is
<interfacename>RequestCallback</interfacename> and is called when the
execute method is invoked.</para>
<programlisting language="java">public &lt;T&gt; T execute(String url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor&lt;T&gt; responseExtractor,
String... urlVariables)
// also has an overload with urlVariables as a Map&lt;String, String&gt;.</programlisting>
<para>The <interfacename>RequestCallback</interfacename> interface is
defined as</para>
<programlisting language="java">public interface RequestCallback {
void doWithRequest(ClientHttpRequest request) throws IOException;
}</programlisting>
<para>and allows you to manipulate the request headers and write to the
request body. When using the execute method you do not have to worry
about any resource management, the template will always close the
request and handle any errors. Refer to the API documentation for more
information on using the execute method and the meaning of its other
method arguments.</para>
</section>
<section id="rest-message-conversion">
<title>HTTP Message Conversion</title>
<para>Objects passed to and returned from the methods
<methodname>getForObject</methodname>,
<methodname>postForLocation</methodname>, and
<methodname>put</methodname> are converted to HTTP requests and from
HTTP responses by <interfacename>HttpMessageConverters</interfacename>.
The <interfacename>HttpMessageConverter</interfacename> interface is
shown below to give you a better feel for its functionality</para>
<programlisting language="java">public interface HttpMessageConverter&lt;T&gt; {
// Indicate whether the given class is supported by this converter.
boolean supports(Class&lt;? extends T&gt; clazz);
// Return the list of MediaType objects supported by this converter.
List&lt;MediaType&gt; getSupportedMediaTypes();
// Read an object of the given type form the given input message, and returns it.
T read(Class&lt;T&gt; clazz, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException;
// Write an given object to the given output message.
void write(T t, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException;
}</programlisting>
<para>Concrete implementations for the main media (mime) types are
provided in the framework and are registered by default with the
<classname>RestTemplate</classname> on the client-side and with
<classname>AnnotationMethodHandlerAdapter</classname> on the
server-side.</para>
<para>The implementations of
<classname>HttpMessageConverter</classname>s are described in the
following sections. For all converters a default media type is used but
can be overridden by setting the
<classname>supportedMediaTypes</classname> bean property</para>
<section id="rest-string-converter">
<title>StringHttpMessageConverter</title>
<para>An <interfacename>HttpMessageConverter</interfacename>
implementation that can read and write Strings from the HTTP request
and response. By default, this converter supports all text media types
(<literal>text/*</literal>), and writes with a
<literal>Content-Type</literal> of
<literal>text/plain</literal>.</para>
</section>
<section id="rest-form-converter">
<title>FormHttpMessageConverter</title>
<para>An <interfacename>HttpMessageConverter</interfacename>
implementation that can read and write form data from the HTTP request
and response. By default, this converter reads and writes the media
type <literal>application/x-www-form-urlencoded</literal>. Form data
is read from and written into a <literal>MultiValueMap&lt;String,
String&gt;</literal>.</para>
</section>
<section id="rest-byte-converter">
<title>ByteArrayMessageConverter</title>
<para>An <interfacename>HttpMessageConverter</interfacename>
implementation that can read and write byte arrays from the HTTP
request and response. By default, this converter supports all media
types (<literal>*/*</literal>), and writes with a
<literal>Content-Type</literal> of
<literal>application/octet-stream</literal>. This can be overridden by
setting the <property>supportedMediaTypes</property> property, and
overriding <literal>getContentType(byte[])</literal>.</para>
</section>
<section id="rest-marhsalling-converter">
<title>MarshallingHttpMessageConverter</title>
<para>An <interfacename>HttpMessageConverter</interfacename>
implementation that can read and write XML using Spring's
<interfacename>Marshaller</interfacename> and
<interfacename>Unmarshaller</interfacename> abstractions from the
<classname>org.springframework.oxm</classname> package. This converter
requires a <interfacename>Marshaller</interfacename> and
<interfacename>Unmarshaller</interfacename> before it can be used.
These can be injected via constructor or bean properties. By default
this converter supports (<literal>text/xml</literal>) and
(<literal>application/xml</literal>).</para>
</section>
<section id="rest-source-converter">
<title>SourceHttpMessageConverter</title>
<para>An <interfacename>HttpMessageConverter</interfacename>
implementation that can read and write
<classname>javax.xml.transform.Source</classname> from the HTTP
request and response. Only <classname>DOMSource</classname>,
<classname>SAXSource</classname>, and
<classname>StreamSource</classname> are supported. By default, this
converter supports (<literal>text/xml</literal>) and
(<literal>application/xml</literal>).</para>
</section>
<section id="rest-source-converter">
<title>BufferedImageHttpMessageConverter</title>
<para>An <interfacename>HttpMessageConverter</interfacename>
implementation that can read and write
<classname>java.awt.image.BufferedImage</classname> from the HTTP
request and response. This converter reads and writes the media type
supported by the Java I/O API.</para>
</section>
</section>
</section>
</chapter>