DATAREST-252 - Documentation overhaul.

Updated documentation and removed obsolete parts.
This commit is contained in:
Oliver Gierke
2014-02-24 09:13:26 +01:00
parent 9ac9ca4d86
commit afe2bd9361
10 changed files with 806 additions and 1293 deletions

View File

@@ -2,7 +2,7 @@
<chapter xml:id="events-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd">
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd">
<title>Events</title>

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0"
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd"
xml:id="install-chapter" xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ns="http://docbook.org/ns/docbook">
<title xml:id="getting-started">Getting started</title>
<section>
<title xml:id="getting-started.introduction">Introduction</title>
<para>Spring Data REST is itself a Spring MVC application and is designed
in such a way that it should integrate with your existing Spring MVC
applications with very little effort. An existing (or future) layer of
services can run alongside Spring Data REST with only minor
considerations.</para>
<para>To install Spring Data REST alongside your application, simply add
the required dependencies, include the stock <code>@Configuration</code>
class <classname>RepositoryRestMvcConfiguration</classname> (or subclass
it and perform any required manual configuration), and map some URLs to be
managed by Spring Data REST.</para>
</section>
<section>
<title xml:base="getting-started.gradle">Adding Spring Data REST to a
Gradle project</title>
<para>To add Spring Data REST to a Gradle-based project, add the
<code>spring-data-rest-webmvc</code> artifact to your compile-time
dependencies: <programlisting language="groovy">dependencies {
… other project dependencies
compile "org.springframework.data:spring-data-rest-webmvc:${spring-data-rest-version}"
}</programlisting></para>
</section>
<section>
<title xml:id="getting-started.maven">Adding Spring Data REST to a Maven
project</title>
<para>To add Spring Data REST to a Maven-based project, add the
<code>spring-data-rest-webmvc</code> artifact to your compile-time
dependencies: <programlisting language="xml">&lt;dependency&gt;
&lt;groupId&gt;org.springframework.data&lt;/groupId&gt;
&lt;artifactId&gt;spring-data-rest-webmvc&lt;/artifactId&gt;
&lt;version&gt;${spring-data-rest-version}&lt;/version&gt;
&lt;/dependency&gt;</programlisting></para>
</section>
<section>
<title xml:id="getting-started.configuration">Configuring Spring Data
REST</title>
<para>To install Spring Data REST alongside your existing Spring MVC
application, you need to include the appropriate MVC configuration. Spring
Data REST configuration is defined in a class called
<classname>RepositoryRestMvcConfiguration</classname>. You can either
import this class into your existing configuration using an
<code>@Import</code> annotation or you can subclass it and override any of
the <code>configureXXX</code> methods to add your own configuration to
that of Spring Data REST.</para>
<para>In the following example, we'll subclass the standard
<classname>RepositoryRestMvcConfiguration</classname> and add some
<classname>ResourceMapping</classname> configurations for the
<classname>Person</classname> domain object to alter how the JSON will
look and how the links to related entities will be handled.
<programlisting language="java">@Configuration
@Import(RepositoryRestMvcConfiguration.class)
public class MyWebConfiguration extends RepositoryRestMvcConfiguration {
// … further configuration
}</programlisting></para>
<para>Make sure you also configure Spring Data repositories for the store
you use. For details on that, please consult the reference documentation
for the corresponding Spring Data module.</para>
</section>
<section>
<title xml:id="getting-started.bootstrap">Starting the application</title>
<para>As Spring Data REST is build on SpringMVC, you simply stick to the
means you use to bootstrap Spring MVC. In a Servlet 3.0 environment this
might look something like this:</para>
<para><programlisting language="java">public class RestExporterWebInitializer implements WebApplicationInitializer {
@Override public void onStartup(ServletContext servletContext) throws ServletException {
// Bootstrap repositories in root application context
AnnotationConfigWebApplicationContext rootCtx = new AnnotationConfigWebApplicationContext();
rootCtx.register(JpaRepositoryConfig.class); // Include JPA entities, Repositories
servletContext.addListener(new ContextLoaderListener(rootCtx));
// Enable Spring Data REST in the DispatcherServlet
AnnotationConfigWebApplicationContext webCtx = new AnnotationConfigWebApplicationContext();
webCtx.register(MyWebConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(webCtx);
ServletRegistration.Dynamic reg = servletContext.addServlet("rest-exporter", dispatcherServlet);
reg.setLoadOnStartup(1);
reg.addMapping("/*");
}
}</programlisting></para>
<para>The equivalent of the above in a standard web.xml will also work
identically to this configuration if you are still in a servlet 2.5
environment. When you deploy this application to your servlet container,
you should be able to see what repositories are exported by accessing the
root of the application.</para>
</section>
</chapter>

View File

@@ -1,53 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<book xml:id="spring-data-rest-reference"
<book version="5.0"
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd"
xml:id="spring-data-rest-reference"
xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd">
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ns="http://docbook.org/ns/docbook">
<info>
<title>Spring Data REST Reference Documentation</title>
<productname>Spring Data REST</productname>
<releaseinfo>${version}</releaseinfo>
<releaseinfo>version;</releaseinfo>
<authorgroup>
<author>
<personname>
<firstname>Jon</firstname>
<surname>Brisbin</surname>
</personname>
<personname><firstname>Jon</firstname>
<surname>Brisbin</surname></personname>
</author>
<author>
<personname>
<firstname>Oliver</firstname>
<surname>Gierke</surname>
</personname>
<personname><firstname>Oliver</firstname>
<surname>Gierke</surname></personname>
</author>
</authorgroup>
<copyright>
<year>2012-2013</year>
<year>2012-2014</year>
</copyright>
<legalnotice>
<para>Copies of this document may be made for your own use and for distribution to others, provided that you do
not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether
distributed in print or electronically.
</para>
<para>Copies of this document may be made for your own use and for
distribution to others, provided that you do not charge any fee for such
copies and further provided that each copy contains this Copyright
Notice, whether distributed in print or electronically.</para>
</legalnotice>
</info>
<toc>
</toc>
<toc/>
<xi:include href="intro.xml"/>
<xi:include href="install.xml"/>
<xi:include href="representations.xml"/>
<xi:include href="paging.xml"/>
<xi:include href="validation.xml"/>
<xi:include href="events.xml"/>
<xi:include href="rest-shell.xml"/>
</book>
<xi:include href="getting-started.xml"/>
<xi:include href="repository-resources.xml" />
<xi:include href="representations.xml"/>
<xi:include href="validation.xml"/>
<xi:include href="events.xml"/>
</book>

View File

@@ -1,190 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="install-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd">
<title>Installing Spring Data REST</title>
<section>
<title>Introduction</title>
<para>Spring Data REST is itself a Spring MVC application and is designed in such a way that it should integrate
with your existing Spring MVC applications with very little effort. An existing (or future) layer of services can
run alongside Spring Data REST with only minor considerations.
</para>
<para>To install Spring Data REST alongside your application, simply add the required dependencies, include the
stock
<code>@Configuration</code>
class (or subclass it and perform any required manual configuration), and map some URLs to be managed by Spring
Data REST.
</para>
</section>
<section>
<title>Adding Spring Data REST to a Gradle project</title>
<para>To add Spring Data REST to a Gradle-based project, add the
<code>spring-data-rest-webmvc</code>
artifact to your compile-time dependencies:
<programlisting><![CDATA[dependencies {
... other project dependencies
compile "org.springframework.data:spring-data-rest-webmvc:1.1.0.M1"
}]]></programlisting>
</para>
</section>
<section>
<title>Adding Spring Data REST to a Maven project</title>
<para>To add Spring Data REST to a Maven-based project, add the
<code>spring-data-rest-webmvc</code>
artifact to your compile-time dependencies:
<programlisting><![CDATA[<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>1.1.0.M1</version>
</dependency>]]></programlisting>
</para>
</section>
<section>
<title>Configuring Spring Data REST</title>
<para>To install Spring Data REST alongside your existing Spring MVC application, you need to include the
appropriate MVC configuration. Spring Data REST configuration is defined in a class called
<classname>RepositoryRestMvcConfiguration</classname>. You can either import this class into your existing
configuration using an
<code>@Import</code>
annotation or you can subclass it and override any of the
<code>configureXXX</code>
methods to add your own configuration to that of Spring Data REST.
</para>
<para>In the following example, we'll subclass the standard
<classname>RepositoryRestMvcConfiguration</classname>
and add some
<classname>ResourceMapping</classname>
configurations for the
<classname>Person</classname>
domain object to alter how the JSON will look and how the links to related entities will be handled.
<programlisting language="java"><![CDATA[
@Configuration
public class MyWebConfiguration extends RepositoryRestMvcConfiguration {
@Override protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.addResourceMappingForDomainType(Person.class)
.addResourceMappingFor("lastName")
.setPath("surname"); // Change 'lastName' to 'surname' in the JSON
config.addResourceMappingForDomainType(Person.class)
.addResourceMappingFor("siblings")
.setRel("siblings")
.setPath("siblings"); // Pointless in this example,
// but shows how to change 'rel' and 'path' values.
}
}
]]></programlisting>
</para>
<para>There are numerous methods on the
<classname>RepositoryRestConfiguration</classname>
object to allow you to configure various aspects of Spring Data REST. Please read the javadoc for that class to
get detailed descriptions of the various settings you can control.
</para>
<section>
<title>Adding custom converters</title>
<para>It may be necessary to add a custom converter to Spring Data REST. You might need to turn a query parameter
into a complex object, for instance. In that case, you'll want to override the
<code>configureConversionService</code>
method and add your own converters. To convert a query parameter to a complex object, for instance, you would
want to register a converter for
<classname>String[]</classname>
to
<classname>MyPojo</classname>.
<programlisting language="java"><![CDATA[
@Bean public MyPojoConverter myPojoConverter() {
return new MyPojoConverter();
}
@Override protected void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(String[].class, myPojoConverter());
}]]></programlisting>
</para>
</section>
</section>
<section>
<title>Adding Spring Data REST to Spring MVC</title>
<para>Since Spring Data REST is simply a Spring MVC application, you only need to include the REST configuration
into the configuration for the
<classname>DispatcherServlet</classname>. If using a Servlet 3.0
<classname>WebApplicationInitializer</classname>
(the preferred configuration for Spring Data REST applications), you would add your subclassed configuration
from above into the configuration for the
<classname>DispatcherServlet</classname>. The following configuration class is from the example project and
includes datasource configuration for three different datastores and domain models, which will all be exported
by Spring Data REST.
<programlisting language="java"><![CDATA[
public class RestExporterWebInitializer implements WebApplicationInitializer {
@Override public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootCtx = new AnnotationConfigWebApplicationContext();
rootCtx.register(
JpaRepositoryConfig.class, // Include JPA entities, Repositories
MongoDbRepositoryConfig.class, // Include MongoDB document entities, Repositories
GemfireRepositoryConfig.class // Inlucde Gemfire entities, Repositories
);
servletContext.addListener(new ContextLoaderListener(rootCtx));
AnnotationConfigWebApplicationContext webCtx = new AnnotationConfigWebApplicationContext();
webCtx.register(MyWebConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(webCtx);
ServletRegistration.Dynamic reg = servletContext.addServlet("rest-exporter", dispatcherServlet);
reg.setLoadOnStartup(1);
reg.addMapping("/*");
}
}]]></programlisting>
</para>
<para>The equivalent of the above in a standard web.xml will also work identically to this configuration if you
are still in a servlet 2.5 environment.
</para>
<para>When you deploy this application to your servlet container, you should be able to see what
repositories are exported by accessing the root of the application. You can use curl or, more easily, the
<code>rest-shell</code>:
<programlisting><![CDATA[$ rest-shell
___ ___ __ _____ __ _ _ _ _ __
| _ \ __/' _/_ _/' _/| || | / / | \ \
| v / _|`._`. | | `._`.| >< | / / / > >
|_|_\___|___/ |_| |___/|_||_| |_/_/ /_/
1.2.1.RELEASE
Welcome to the REST shell. For assistance hit TAB or type "help".
http://localhost:8080:> list
rel href
==========================================
people http://localhost:8080/people
profile http://localhost:8080/profile
customer http://localhost:8080/customer
order http://localhost:8080/order
product http://localhost:8080/product
]]></programlisting>
</para>
</section>
</chapter>

View File

@@ -1,171 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="intro-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
<chapter xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd http://www.w3.org/1999/xlink http://docbook.org/xml/5.0/xsd/xlink.xsd"
xml:id="intro-chapter" xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.oasis-open.org/docbook/xml/5.0/xsd/xlink.xsd">
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ns="http://docbook.org/ns/docbook">
<title>Introduction</title>
<para>Spring Data REST makes exporting domain objects to RESTful clients using
<link
xlink:href="http://en.wikipedia.org/wiki/HATEOAS">HATEOAS
</link>
principles very easy. It exposes the CRUD methods of the Spring Data
<link
xlink:href="http://static.springsource.org/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html">
<classname>CrudRepository</classname>
</link>
interface to HTTP. Spring Data REST also reads the body of HTTP requests and interprets them as domain objects. It
recognizes relationships between entities and represents that relationship in the form of a<code>Link</code>.
</para>
<para>REST web services have become the number one means for application
integration on the web. In its core, REST defines that a system consists of
resources that clients interact with. These resources are implemented in a
hypermedia drive way. Spring MVC offers a solid foundation to build theses
kinds of services but implementic very basic functionality of REST web
service can be tedious and result in a lot of boilderplate code.</para>
<section>
<title>HTTP Verb to CRUD Method Mapping</title>
<para>Spring Data REST translates HTTP calls to method calls by mapping the HTTP verbs to CRUD methods. The
following table illustrates the way in which an HTTP verb is mapped to a
<code>CrudRepository</code>
method.
</para>
<table>
<caption>HTTP verb to CRUD method mapping</caption>
<thead>
<tr>
<th>Verb</th>
<th>Method</th>
</tr>
</thead>
<tr>
<td>
<code>GET</code>
</td>
<td>
<code>CrudRepository&lt;ID,T&gt;.findOne(ID id)</code>
</td>
</tr>
<tr>
<td>
<code>POST</code>
</td>
<td>
<code>CrudRepository&lt;ID,T&gt;.save(T entity)</code>
</td>
</tr>
<tr>
<td>
<code>PUT</code>
</td>
<td>
<code>CrudRepository&lt;ID,T&gt;.save(T entity)</code>
</td>
</tr>
<tr>
<td>
<code>DELETE</code>
</td>
<td>
<code>CrudRepository&lt;ID,T&gt;.delete(ID id)</code>
</td>
</tr>
</table>
<para>By default, all of these methods are exported to clients. By placing an annotation on your
<classname>CrudRepository</classname>
subinterface, however, you can turn access to a method off. This is discussed in more detail in the section on
configuration.
</para>
</section>
<section xml:id="hateoas-discoverability">
<title>Resource Discoverability</title>
<para>A core principle of HATEOAS is that resources should be discoverable through the publication of links that
point to the available resources. There are a number of ways to accomplish this but no real standard way. Spring
Data REST uses a link method that is consistent across Spring Data REST: it provides links in a property called
<code>links</code>. That property is an array of objects that take the form of something resembling an
<link xlink:href="http://tools.ietf.org/html/rfc4287#section-4.2.7">atom:link</link>
element in the
<link xlink:href="http://tools.ietf.org/html/rfc4287">Atom XML namespace</link>.
</para>
<para>Resource discovery starts at the top level of the application. By issuing a request to the root URL under
which the Spring Data REST application is deployed, the client can extract a set of links from the returned JSON
object that represent the next level of resources that are available to the client.
</para>
<para>For example, to discover what resources are available at the root of the application, issue an HTTP GET to
the root URL:
</para>
<programlisting><![CDATA[curl -v http://localhost:8080/
< HTTP/1.1 200 OK
< Content-Type: application/json
<
{
"links" : [ {
"rel" : "customer",
"href" : "http://localhost:8080/customer"
}, {
"rel" : "profile",
"href" : "http://localhost:8080/profile"
}, {
"rel" : "order",
"href" : "http://localhost:8080/order"
}, {
"rel" : "people",
"href" : "http://localhost:8080/people"
}, {
"rel" : "product",
"href" : "http://localhost:8080/product"
} ],
"content" : [ ]
}]]></programlisting>
<para>The
<property>links</property>
property of the result document contains an array of objects that have
<property>rel</property>
and
<property>href</property>
properties on them.
</para>
<section>
<title>Compact vs. Verbose</title>
<para>When issuing a request to a resource, the default behavior is to provide as much information as possible in
the body of the response. In the case of accessing a
<classname>Repository</classname>
resource, Spring Data REST will inline entities into the body of the response. This could lead to poor network
performance in the case of a very large number of entities. To reduce the amount of data sent back in the
response, a user agent can request the special content type
<code>application/x-spring-data-compact+json</code>
by placing this in the request
<code>Accept</code>
header. Rather than inlining the entities, this content-type provides a link to each entity in the
<property>links</property>
property.
</para>
<programlisting><![CDATA[curl -v -H "Accept: application/x-spring-data-compact+json" http://localhost:8080/customer
< HTTP/1.1 200 OK
< Content-Type: application/x-spring-data-compact+json
<
{
"links" : [ {
"rel" : "customer.search",
"href" : "http://localhost:8080/customer/search"
} ],
"content" : [ ]
}]]></programlisting>
</section>
</section>
</chapter>
<para>Spring Data REST builds on top of Spring Data repositories and
automatically exports those as REST resources. It leverages hypermedia to
allow clients to find functionality exposed by the repositories and allows
to integrate the resources into related hypermedia based functionality as
easy as possible.</para>
</chapter>

View File

@@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="paging-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.oasis-open.org/docbook/xml/5.0/xsd/xlink.xsd">
<title>Paging and Sorting</title>
<section>
<title>Paging</title>
<para>Rather than return everything from a large result set, Spring Data REST recognizes some URL parameters that
will
influence the page size and starting page number. To add paging support to your Repositories, you need to extend
the
<classname>PagingAndSortingRepository&lt;T,ID&gt;</classname>
interface rather than the basic
<classname>CrudRepository&lt;T,ID&gt;</classname>
interface. This adds methods that accept a
<classname>Pageable</classname>
to control the number and page of results returned.
<programlisting language="java"><![CDATA[public Page findAll(Pageable pageable);]]></programlisting>
</para>
<para>If you extend
<classname>PagingAndSortingRepository&lt;T,ID&gt;</classname>
and access the list of all entities, you'll get links to the first 20 entities. To set the page size to any other
number, add a limit parameter:
<programlisting><![CDATA[http://localhost:8080/people/?limit=50]]></programlisting>
</para>
<para>To get paging in your query methods, you must change the signature of your query methods to accept a
<classname>Pageable</classname>
as a parameter and return a
<classname>Page&lt;T&gt;</classname>
rather than a
<classname>List&lt;T&gt;</classname>. Otherwise, you won't get any paging information in the JSON and
specifying the query parameters that control paging will have no effect.
</para>
<para>By default, the URL query parameters recognized are
<code>page</code>, to specify page number
<code>limit</code>, to specify how many results to return on a page, and
<code>sort</code>
to specify the query method parameter on which to sort. To change the names of the query parameters, simply call
the appropriate method on
<classname>RepositoryRestConfiguration</classname>
and give it the text you would like to use for the query parameter. The following, for example, would set the
paging parameter to
<code>p</code>, the limit parameter to
<code>l</code>, and the sort parameter to
<code>q</code>:
<programlisting language="java"><![CDATA[
@Override protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.setPageParamName("p")
.setLimitParamName("l")
.setSortParamName("q");
}]]></programlisting>
</para>
<para>The URL to use these parameters would then be changed to:
<programlisting><![CDATA[http://localhost:8080/people/?p=2&l=50]]></programlisting>
</para>
<section>
<title>Previous and Next Links</title>
<para>Each paged response will return links to the previous and next pages of results based on the current page.
If
you are currently at the first page of results, however, no "previous" link will be rendered. The same is true
for
the last page of results: no "next" link will be rendered if you are on the last page of results. The "rel"
value
of the link will end with ".next" for next links and ".prev" for previous links.
<programlisting><![CDATA[{
"rel" : "people.next",
"href" : "http://localhost:8080/people?page=2&limit=20"
}]]></programlisting>
</para>
</section>
</section>
<section>
<title>Sorting</title>
<para>Spring Data REST also recognizes sorting parameters that will use the Repository sorting support.</para>
<para>To have your results sorted on a particular property, add a sort URL parameter with the name of the property
you want to sort the results on. You can control the direction of the sort by specifying a URL parameter composed
of the property name plus
<code>.dir</code>
and setting that value to either
<code>asc</code>
or<code>desc</code>. The following would use the
<code>findByNameStartsWith</code>
query method defined on the
<classname>PersonRepository</classname>
for all
<classname>Person</classname>
entities with names starting with the letter "K" and add sort data that orders the results on the name property in
descending order:
<programlisting>
<![CDATA[curl -v http://localhost:8080/people/search/nameStartsWith?name=K&sort=name&name.dir=desc]]></programlisting>
</para>
</section>
</chapter>

View File

@@ -0,0 +1,578 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter version="5.0"
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd"
xml:id="repository-resources" xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ns="http://docbook.org/ns/docbook">
<title>Repository resources</title>
<section xml:id="repository-resources.fundamentals">
<title>Fundamentals</title>
<para>The core functionality of Spring Data REST is to export resources
for Spring Data repositories. Thus, the core artifact to look at and
potentially tweak to customize the way the exporting works is the
repository interface. Assume the following repository interface:</para>
<programlisting>public interface OrderRepository extends CrudRepository&lt;Order, Long&gt; { }</programlisting>
<para>For this repository, Spring Data REST exposes a collection resource
at <code>/orders</code>. The path is derived from the uncapitalized,
pluralized, simple class name of the domain class being managed. It also
exposes a an item resource for each of the items managed by te repository
under the URI template <uri>/orders/{id}</uri>. </para>
<para>By default the HTTP methods to interact with these resources map to
the according methods of <interfacename>CrudRepository</interfacename>.
Read more on that in the sections on <link
linkend="repository-resources.collection-resource">collection
resources</link> and <link
linkend="repository-resources.item-resource">item resources</link>.</para>
<section xml:id="repository-resources.default-status-codes">
<title>Default status codes</title>
<para>For the resources exposed, we use a set of default status
codes:</para>
<itemizedlist>
<listitem>
<para><code>200 OK</code> - for plain <code>GET</code>
requests.</para>
</listitem>
<listitem>
<para><code>201 Created</code> - for <code>POST</code> and
<code>PUT</code> requests that create new resources.</para>
</listitem>
<listitem>
<para><code>204 No Content</code> - for <code>PUT</code>,
<code>PATCH</code>, and <code>DELETE</code> requests if the
configuration is set to not return response bodies for resource
updates
(<code>RepositoryRestConfiguration.returnBodyOnUpdate</code>). If
the configuration value is set to include responses for
<code>PUT</code>, <code>200 OK</code> will be returned for updates,
<code>201 Created</code> will be returned for resource created
through <code>PUT</code>.</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="repository-resources.resource-discoverability">
<title>Resource discoverability</title>
<para>A core principle of HATEOAS is that resources should be
discoverable through the publication of links that point to the
available resources. There are a few competing de-facto standards of how
to represent links in JSON. By default, Spring Data REST uses <link
xlink:href="http://tools.ietf.org/html/draft-kelly-json-hal">HAL</link>
to render responses. HAL defines links to be contained in a
<property>_link</property> property of the returned document.</para>
<para>Resource discovery starts at the top level of the application. By
issuing a request to the root URL under which the Spring Data REST
application is deployed, the client can extract a set of links from the
returned JSON object that represent the next level of resources that are
available to the client.</para>
<para>For example, to discover what resources are available at the root
of the application, issue an HTTP <code>GET</code> to the root
URL:</para>
<programlisting>curl -v http://localhost:8080/
&lt; HTTP/1.1 200 OK
&lt; Content-Type: application/hal+json
{ "_links" : {
"orders" : {
"href" : "http://localhost:8080/orders"
}
}
}</programlisting>
<para>The <property>_links</property> property of the result document is
an object in itself consisting of keys representing the relation type
with nested link objects as specified in HAL.</para>
</section>
</section>
<section xml:id="repository-resources.collection-resource">
<title>The collection resource</title>
<para>Spring Data REST exposes a collection resource named after the
uncapitalized, pluralized version of the domain class the exported
repository is handling. Both the name of the resource and the path can be
customized using the
<interfacename>@RepositoryRestResource</interfacename> on the repository
interface.</para>
<section>
<title>Supported HTTP Methods</title>
<para>Collections resources support both <code>GET</code> and
<code>POST</code>. All other HTTP methods will cause a <code>405 Method
Not Allowed</code>.</para>
<section>
<title><code>GET</code></title>
<para>Returns all entities the repository servers through its
<methodname>findAll(…)</methodname> method. If the repository is a
paging repository we include the pagination links if necessary and
additional page metadata.</para>
<simplesect>
<title>Parameters</title>
<para>If the repository has pagination capabilities the resource
takes the following parameters:</para>
<itemizedlist>
<listitem>
<para><code>page</code> - the page number to access (0 indexed,
defaults to 0).</para>
</listitem>
<listitem>
<para><code>size</code> - the page size requested (defaults to
20).</para>
</listitem>
<listitem>
<para><code>sort</code> - a collection of sort directives in the
format <code>($propertyname,)+[asc|desc]</code>?.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the
<methodname>findAll(…)</methodname> methods was not exported
(through <code>@RestResource(exported = false)</code>) or is not
present in the repository at all.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Related resources</title>
<itemizedlist>
<listitem>
<para><code>search</code> - a <link
linkend="repository-resources.search-resource">search
resource</link> if the backing repository exposes query
methods.</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
<section>
<title><code>POST</code></title>
<para>Creates a new entity from the given request body.</para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the
<methodname>save(…)</methodname> methods was not exported
(through <code>@RestResource(exported = false)</code>) or is not
present in the repository at all.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
</section>
</section>
<section xml:id="repository-resources.item-resource">
<title>The item resource</title>
<para>Spring Data REST exposes a resource for individual collection items
as sub-resources of the collection resource.</para>
<section>
<title>Supported HTTP methods</title>
<para>Item resources generally support <code>GET</code>,
<code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> unless
explicit configuration prevents that (see below for details).</para>
<section>
<title><code>GET</code></title>
<para>Returns a single entity.</para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the
<methodname>findOne(…)</methodname> methods was not exported
(through <code>@RestResource(exported = false)</code>) or is not
present in the repository at all.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Related resources</title>
<para>For every association of the domain type we expose links named
after the association property. This can be customized by using
<interfacename>@RestResource</interfacename> on the property. The
related resources are of type <link
linkend="repository-resources.association-resource">association
resource</link>.</para>
</simplesect>
</section>
<section>
<title><code>PUT</code></title>
<para>Replaces the state of the target resource with the supplied
request body.</para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the
<methodname>save(…)</methodname> methods was not exported
(through <code>@RestResource(exported = false)</code>) or is not
present in the repository at all.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
<section>
<title><code>PATCH</code></title>
<para>Similar to <code>PUT</code> but only applying values sent with
the request body.</para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the
<methodname>save(…)</methodname> methods was not exported
(through <code>@RestResource(exported = false)</code>) or is not
present in the repository at all.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
<section>
<title><code>DELETE</code></title>
<para>Deletes the resource exposed.</para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the
<methodname>delete(…)</methodname> methods was not exported
(through <code>@RestResource(exported = false)</code>) or is not
present in the repository at all.</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
</section>
</section>
<section xml:id="repository-resources.association-resource">
<title>The association resource</title>
<para>Spring Data REST exposes sub-resources of every item resource for
each of the associations the item resource has. The name and path of the
of the resource defaults to the name of the association property and can
be customized using <interfacename>@RestResource</interfacename> on the
association property. </para>
<section>
<title>Supported HTTP methods</title>
<section>
<title>GET</title>
<para>Reutrns the state of the association resource</para>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
<section>
<title>PUT</title>
<para>Binds the resource pointed to by the given URI(s) to the
resource. This </para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>400 Bad Request</code> - if multiple URIs were given
for a to-one-association.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>text/uri-list - URIs pointing to the resource to bind to
the association.</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
<section>
<title>POST</title>
<para>Only supported for collection associations. Adds a new element
to the collection.</para>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>text/uri-list - URIs pointing to the resource to add to
the association.</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
<section>
<title>DELETE</title>
<para>Unbinds the association.</para>
<simplesect>
<title>Custom status codes</title>
<itemizedlist>
<listitem>
<para><code>405 Method Not Allowed</code> - if the association
is non-optional.</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
</section>
</section>
<section xml:id="repository-resources.search-resource">
<title>The search resource</title>
<para>The search resource returns links for all query methods exposed by a
repository. The path and name of the query method resources can be
modified using <interfacename>@RestResource</interfacename> on the method
declaration.</para>
<section>
<title>Supported HTTP methods</title>
<para>As the search resource is a read-only resource it supports
<code>GET</code> only.</para>
<section>
<title><code>GET</code></title>
<para>Returns a list of links pointing to the individual query method
resources</para>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Related resources</title>
<para>For every query method declared in the repository we expose a
<link linkend="repository-resources.query-method-resource">query
method resource</link>. If the resource supports pagination, the URI
pointing to it will be a URI template containing the pagination
parameters.</para>
</simplesect>
</section>
</section>
</section>
<section xml:id="repository-resources.query-method-resource">
<title>The query method resource</title>
<para>The query method resource executes the query exposed through an
individual query method on the repository interface.</para>
<section>
<title>Supported HTTP methods</title>
<para>As the search resource is a read-only resource it supports
<code>GET</code> only.</para>
<section>
<title><code>GET</code></title>
<para>Returns the result of the query execution.</para>
<simplesect>
<title>Parameters</title>
<para>If the query method has pagination capabilities (indicated in
the URI template pointing to the resource) the resource takes the
following parameters:</para>
<itemizedlist>
<listitem>
<para><code>page</code> - the page number to access (0 indexed,
defaults to 0).</para>
</listitem>
<listitem>
<para><code>size</code> - the page size requested (defaults to
20).</para>
</listitem>
<listitem>
<para><code>sort</code> - a collection of sort directives in the
format <code>($propertyname,)+[asc|desc]</code>?.</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect>
<title>Supported media types</title>
<itemizedlist>
<listitem>
<para>application/hal+json</para>
</listitem>
<listitem>
<para>application/json</para>
</listitem>
</itemizedlist>
</simplesect>
</section>
</section>
</section>
</chapter>

View File

@@ -1,175 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="representations-chapter"
<chapter xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd http://www.w3.org/1999/xlink http://docbook.org/xml/5.0/xsd/xlink.xsd"
xml:id="representations-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.oasis-open.org/docbook/xml/5.0/xsd/xlink.xsd">
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ns="http://docbook.org/ns/docbook">
<title>Domain Object Representations</title>
<section xml:id="links">
<title>Links as First-Class Objects</title>
<para>Links are an essential part of RESTful resources and allow for easy discoverability of related resources. In
Spring Data REST, a link is represented in JSON as an object with a
<code>rel</code>
and
<code>href</code>
property. These objects will appear in an array under an object's
<code>links</code>
property. These objects are meant to provide a user agent with the URLs necessary to retrieve resources related to
the current resource being accessed.
</para>
<para>When accessing the root of a Spring Data REST application, for example, links are provided to each repository
that is exported. The user agent can then pick the link it is interested in and follow that<code>href</code>.
Issue a
<code>get</code>
in the
<code>rest-shell</code>
to see an example of links.
<programlisting><![CDATA[
http://localhost:8080:> get
> GET http://localhost:8080/
< 200 OK
< Content-Type: application/json
<
{
"links" : [ {
"rel" : "people",
"href" : "http://localhost:8080/people"
}, {
"rel" : "profile",
"href" : "http://localhost:8080/profile"
}, {
"rel" : "customer",
"href" : "http://localhost:8080/customer"
}, {
"rel" : "order",
"href" : "http://localhost:8080/order"
}, {
"rel" : "product",
"href" : "http://localhost:8080/product"
} ],
"content" : [ ]
}]]></programlisting>
</para>
<section>
<title>Entity Relationships</title>
<para>If two entities are related to one another through a database-defined relationship, then that relationship
will appear in the JSON as a link. In JPA, one would place a
<code>@ManyToOne</code>,
<code>@OneToOne</code>, or other relationship annotation. If using Spring Data MongoDB, one would place a
<code>@DBRef</code>
annotation on a property to denote its special status as a reference to other entities. In the example project,
the
<classname>Person</classname>
class has a related set of
<classname>Person</classname>
entities in the
<code>siblings</code>
property. If you
<code>get</code>
the resource of a
<classname>Person</classname>
you will see, in the
<code>siblings</code>
property, the link to follow to get the related
<classname>Person</classname>s.
<programlisting><![CDATA[
http://localhost:8080:> get people/1
> GET http://localhost:8080/people/1
< 200 OK
< Content-Type: application/json
<
{
"firstName" : "Billy Bob",
"surname" : "Thornton",
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/people/1"
}, {
"rel" : "people.person.father",
"href" : "http://localhost:8080/people/1/father"
}, {
"rel" : "people.person.siblings",
"href" : "http://localhost:8080/people/1/siblings"
} ]
}]]></programlisting>
</para>
</section>
</section>
<section xml:id="mapping">
<title>Object Mapping</title>
<para>Spring Data REST returns a representation of a domain object that corresponds to the requested
<code>Accept</code>
type specified in the HTTP request.
<footnote>
<para>Currently, only JSON representations are supported. Other representation types can be supported in the
future by adding an appropriate converter and updating the controller methods with the appropriate
content-type.
</para>
</footnote>
</para>
<para>Spring Data REST returns a representation of a domain object that
corresponds to the requested <code>Accept</code> type specified in the
HTTP request. <footnote>
<para>Currently, only JSON representations are supported. Other
representation types can be supported in the future by adding an
appropriate converter and updating the controller methods with the
appropriate content-type.</para>
</footnote></para>
<para>Sometimes the behavior of the Spring Data REST's ObjectMapper, which has been specially configured to use
intelligent serializers that can turn domain objects into links and back again, may not handle your domain model
correctly. There are so many ways one can structure your data that you may find your own domain model isn't being
translated to JSON correctly. It's also sometimes not practical in these cases to try and support a complex domain
model in a generic way. Sometimes, depending on the complexity, it's not even possible to offer a generic
solution.
</para>
<para>Sometimes the behavior of the Spring Data REST's ObjectMapper, which
has been specially configured to use intelligent serializers that can turn
domain objects into links and back again, may not handle your domain model
correctly. There are so many ways one can structure your data that you may
find your own domain model isn't being translated to JSON correctly. It's
also sometimes not practical in these cases to try and support a complex
domain model in a generic way. Sometimes, depending on the complexity,
it's not even possible to offer a generic solution.</para>
<section>
<title>Adding custom (de)serializers to Jackson's ObjectMapper</title>
<para>To accommodate the largest percentage of use cases, Spring Data REST tries very hard to render your
object graph correctly. It will try and serialize unmanaged beans as normal POJOs and it will try and create
links to managed beans where that's necessary. But if your domain model doesn't easily lend itself to reading or
writing plain JSON, you may want to configure Jackson's ObjectMapper with your own custom type mappings and
(de)serializers.
</para>
<para>To accommodate the largest percentage of use cases, Spring Data
REST tries very hard to render your object graph correctly. It will try
and serialize unmanaged beans as normal POJOs and it will try and create
links to managed beans where that's necessary. But if your domain model
doesn't easily lend itself to reading or writing plain JSON, you may
want to configure Jackson's ObjectMapper with your own custom type
mappings and (de)serializers.</para>
<section>
<title>Abstract class registration</title>
<para>One key configuration point you might need to hook into is when you're using an abstract class (or an
interface) in your domain model. Jackson won't know by default what implementation to create for an interface.
Take the following example:
</para>
<para>One key configuration point you might need to hook into is when
you're using an abstract class (or an interface) in your domain model.
Jackson won't know by default what implementation to create for an
interface. Take the following example:</para>
<programlisting language="java"><![CDATA[@Entity
<programlisting language="java">@Entity
public class MyEntity {
@OneToMany
private List<MyInterface> interfaces;
}]]></programlisting>
private List&lt;MyInterface&gt; interfaces;
}</programlisting>
<para>In a default configuration, Jackson has no idea what class to instantiate when POSTing new data to the
exporter. This is something you'll need to tell Jackson either through an annotation, or, more cleanly, by
registering a type mapping using a
<classname>Module</classname>.
</para>
<para>In a default configuration, Jackson has no idea what class to
instantiate when POSTing new data to the exporter. This is something
you'll need to tell Jackson either through an annotation, or, more
cleanly, by registering a type mapping using a
<classname>Module</classname>.</para>
<para>To add your own Jackson configuration to the
<classname>ObjectMapper</classname>
used by Spring Data REST, override the
<code>configureJacksonObjectMapper</code>
method. That method will be passed an
<classname>ObjectMapper</classname>
instance that has a special module to handle serializing and deserializing
<classname>PersistentEntity</classname>s. You can register your own modules as well, like in the following
example.
<programlisting language="java"><![CDATA[
<classname>ObjectMapper</classname> used by Spring Data REST, override
the <code>configureJacksonObjectMapper</code> method. That method will
be passed an <classname>ObjectMapper</classname> instance that has a
special module to handle serializing and deserializing
<classname>PersistentEntity</classname>s. You can register your own
modules as well, like in the following example. <programlisting
language="java">
@Override protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
objectMapper.registerModule(new SimpleModule("MyCustomModule"){
@Override public void setupModule(SetupContext context) {
@@ -179,34 +77,27 @@ public class MyEntity {
);
}
});
}]]></programlisting>
</para>
}</programlisting></para>
<para>Once you have access to the
<classname>SetupContext</classname>
object in your
<classname>Module</classname>, you can do all sorts of cool things to
configure Jacskon's JSON mapping. You can read more about how
<classname>Module</classname>s work on Jackson's wiki:
<link xlink:href="http://wiki.fasterxml.com/JacksonFeatureModules">
http://wiki.fasterxml.com/JacksonFeatureModules
</link>
</para>
<para>Once you have access to the <classname>SetupContext</classname>
object in your <classname>Module</classname>, you can do all sorts of
cool things to configure Jacskon's JSON mapping. You can read more
about how <classname>Module</classname>s work on Jackson's wiki: <link
xlink:href="http://wiki.fasterxml.com/JacksonFeatureModules">
http://wiki.fasterxml.com/JacksonFeatureModules </link></para>
</section>
<section>
<title>Adding custom serializers for domain types</title>
<para>If you want to (de)serialize a domain type in a special way, you can register your own implementations
with Jackson's
<classname>ObjectMapper</classname>
and the Spring Data REST exporter will transparently handle those domain objects correctly. To add
serializers, from your
<code>setupModule</code>
method implementation, do something like the following:
</para>
<para>If you want to (de)serialize a domain type in a special way, you
can register your own implementations with Jackson's
<classname>ObjectMapper</classname> and the Spring Data REST exporter
will transparently handle those domain objects correctly. To add
serializers, from your <code>setupModule</code> method implementation,
do something like the following:</para>
<programlisting language="java"><![CDATA[
<programlisting language="java">
@Override public void setupModule(SetupContext context) {
SimpleSerializers serializers = new SimpleSerializers();
SimpleDeserializers deserializers = new SimpleDeserializers();
@@ -216,10 +107,8 @@ public class MyEntity {
context.addSerializers(serializers);
context.addDeserializers(deserializers);
}]]></programlisting>
}</programlisting>
</section>
</section>
</section>
</chapter>
</chapter>

View File

@@ -1,619 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="rest-shell-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.oasis-open.org/docbook/xml/5.0/xsd/xlink.xsd">
<title>Using the
<command>rest-shell</command>
</title>
<para>The
<link xlink:href="https://github.com/SpringSource/rest-shell">
<command>rest-shell</command>
</link>
is a command-line shell that aims to make writing REST-based applications easier. It is based on spring-shell and
integrated with Spring HATEOAS in such a way that REST resources that output JSON compliant with Spring HATEOAS
can be discovered by the shell and interactions with the REST resources become much easier than by manipulating
the URLs in bash using a tool like
<command>curl</command>.
</para>
<para>The rest-shell provides a number of useful commands for discovering and interacting with REST resources. For
example discover will discover what resources are available and print out an easily-readable table of rels and
URIs that relate to those resources. Once these resources have been discovered, the rel of those URIs can be used
in place of the URI itself in most operations, thus cutting down on the amount of typing needed to issue HTTP
requests to your REST resources.
</para>
<section>
<title>Installing the
<command>rest-shell</command>
</title>
<para>If you're using Mac OS X and Homebrew, then installation is super easy:</para>
<programlisting><![CDATA[brew install rest-shell]]></programlisting>
<para>Other platforms are simple as well: just download the archive from the GitHub page and unzip it to a
location on your local hard drive.
</para>
</section>
<section>
<title>Discovering resources</title>
<para>The rest-shell is aimed at making it easier to interact with REST resources by managing the session baseUri
much like a directory in a filesystem. Whenever resources are discovered, you can then follow to a new baseUri,
which means you can then use relative URIs. Here's an example of discovering resources, then following a link by
referencing its rel value, and then using a relative URI to access resources under that new baseUri:
</para>
<programlisting><![CDATA[http://localhost:8080:> discover
rel href
========================================================
address http://localhost:8080/address
family http://localhost:8080/family
people http://localhost:8080/person
profile http://localhost:8080/profile
http://localhost:8080:> follow people
http://localhost:8080/person:> list
rel href
===================================================
people.Person http://localhost:8080/person/1
people.Person http://localhost:8080/person/2
people.search http://localhost:8080/person/search
http://localhost:8080/person:> get 1
> GET http://localhost:8080/person/1
< 200 OK
< ETag: "2"
< Content-Type: application/json
<
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/person/1"
}, {
"rel" : "peeps.Person.profiles",
"href" : "http://localhost:8080/person/1/profiles"
}, {
"rel" : "peeps.Person.addresses",
"href" : "http://localhost:8080/person/1/addresses"
} ],
"name" : "John Doe"
}]]></programlisting>
<para>
<emphasis>NOTE: If you want tab completion of discovered rels, just use the --rel flag.</emphasis>
</para>
</section>
<section>
<title>Creating new resources</title>
<para>The rest-shell can do basic parsing of JSON data within the shell (though there are some limitations due to
the nature of the command line parsing being sensitive to whitespace). This makes it easy to create new
resources
by including JSON data directly in the shell:
</para>
<programlisting><![CDATA[http://localhost:8080/person:> post --data "{name: 'John Doe'}"
> POST http://localhost:8080/person/
< 201 CREATED
< Location: http://localhost:8080/person/8
< Content-Length: 0
<
http://localhost:8080/person:> get 8
> GET http://localhost:8080/person/8
< 200 OK
< ETag: "0"
< Content-Type: application/json
<
{
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/person/8"
}, {
"rel" : "people.Person.addresses",
"href" : "http://localhost:8080/person/8/addresses"
}, {
"rel" : "people.Person.profiles",
"href" : "http://localhost:8080/person/8/profiles"
} ],
"name" : "John Doe"
}]]></programlisting>
<para>If your needs of representing JSON get more complicated than what the spring-shell interface can handle, you
can create a directory somewhere with .json files in it, one file per entitiy, and use the --from option to the
post command. This will walk the directory and make a POST request for each .json file found.
</para>
<programlisting><![CDATA[http://localhost:8080/person:> post --from work/people_to_load
128 items uploaded to the server using POST.
http://localhost:8080/person:>]]></programlisting>
<para>You can also reference a specific file rather than an entire directory.</para>
<programlisting><![CDATA[http://localhost:8080/person:> post --from work/people_to_load/someone.json
1 items uploaded to the server using POST.
http://localhost:8080/person:>]]></programlisting>
</section>
<section>
<title>Passing query parameters</title>
<para>If you're calling URLs that require query parameters, you'll need to pass those as a JSON-like fragment in
the --params parameter to the get and list commands. Here's an example of calling a URL that expects parameter
input:
</para>
<programlisting><![CDATA[http://localhost:8080/person:> get search/byName --params "{name: 'John Doe'}"]]>
</programlisting>
</section>
<section>
<title>Outputing results to a file</title>
<para>It's not always desirable to output the results of an HTTP request to the screen. It's handy for debugging
but
sometimes you want to save the results of a request because they're not easily reproducible or any number of
other
equally valid reasons. All the HTTP commands take an --output parameter that writes the results of an HTTP
operation to the given file. For example, to output the above search to a file:
</para>
<programlisting><![CDATA[http://localhost:8080/person:> get search/byName --params "{name: 'John Doe'}" --output by_name.txt >> by_name.txt
http://localhost:8080/person:>]]></programlisting>
</section>
<section>
<title>Sending complex JSON</title>
<para>Because the rest-shell uses the spring-shell underneath, there are limitations on the format of the JSON
data
you can enter directly into the command line. If your JSON is too complex for the simplistic limitations of the
shell --data parameter, you can simply load the JSON from a file or from all the files in a directory.
</para>
<para>When doing a post or put, you can optionally pass the --from parameter. The value of this parameter should
either be a file or a directory. If the value is a directory, the shell will read each file that ends with .json
and make a POST or PUT with the contents of that file. If the parameter is a file, then the rest-shell will
simpy
load that file and POST/PUT that data in that individual file.
</para>
</section>
<section>
<title>Shelling out to bash</title>
<para>One of the nice things about spring-shell is that you can directly shell out commands to the underlying
terminal shell. This is useful for doing things like load a JSON file in an editor. For instance, assume I have
the Sublime Text 2 command subl in my path. I can then load a JSON file for editing from the rest-shell like
this:
</para>
<programlisting><![CDATA[http://localhost:8080/person:> ! subl test.json
http://localhost:8080/person:>]]></programlisting>
<para>I then edit the file as I wish. When I'm ready to POST that data to the server, I can do so using the --from
parameter:
</para>
<programlisting><![CDATA[http://localhost:8080/person:> post --from test.json
1 items uploaded to the server using POST.
http://localhost:8080/person:>]]></programlisting>
</section>
<section>
<title>Setting context variables</title>
<para>Starting with rest-shell version 1.1, you can also work with context variables during your shell session.
This
is useful for saving settings you might reference often. The rest-shell now integrates Spring Expression
Language
support, so these context variables are usable in expressions within the shell.
</para>
<programlisting><![CDATA[http://localhost:8080/person:> var set --name specialUri --value http://longdomainname.com/api
http://localhost:8080/person:> var get --name specialUri
http://longdomainname.com/api
http://localhost:8080/person:> var list
{
"responseHeaders" : {
... HTTP headers from last request
},
"responseBody" : {
... Body from the last request
},
"specialUri" : "http://longdomainname.com/api",
"requestUrl" : ... URL from the last request,
"env" : {
... System properties and environment variables
}
}]]></programlisting>
<para>The variables are accessible from SpEL expressions which are valid in a number of different contexts, most
importantly in the path argument to the HTTP and discover commands, and in the data argument to the put and post
commands.
</para>
<para>Since the rest-shell is aware of environment variables and system properties, you can incorporate external
parameters into your interaction with the shell. For example, to externally define a baseUri, you could set a
system property before invoking the shell. The shell will incorporate anything defined in the JAVA_OPTS
environment variable, so you could parameterize your interaction with a REST service.
</para>
<programlisting><![CDATA[JAVA_OPTS="-DbaseUri=http://mylongdomain.com/api" rest-shell
http://localhost:8080:> discover #{env.baseUri}
rel href
=================================================================
... resources for this URL
http://mylongdomain.com/api:>]]></programlisting>
</section>
<section>
<title>Per-user shell initialization</title>
<para>The rest-shell supports a "dotrc" type of initialization by reading in all files found in the
$HOME/.rest-shell/ directory and assuming they have shell commands in them. The rest-shell will execute these
commands on startup. This makes it easy to set variables for commonly-used URIs or possibly set a baseUri.
</para>
<programlisting><![CDATA[echo "var set --name svcuri --value http://api.myservice.com/v1" > ~/.rest-shell/00-vars
echo "discover #{svcuri}" > ~/.rest-shell/01-baseUri
> rest-shell
INFO: No resources found...
INFO: Base URI set to 'http://api.myservice.com/v1'
___ ___ __ _____ __ _ _ _ _ __
| _ \ __/' _/_ _/' _/| || | / / | \ \
| v / _|`._`. | | `._`.| >< | / / / > >
|_|_\___|___/ |_| |___/|_||_| |_/_/ /_/
1.2.1.RELEASE
Welcome to the REST shell. For assistance hit TAB or type "help".
http://api.myservice.com/v1:>]]></programlisting>
</section>
<section>
<title>SSL Certificate Validation</title>
<para>If you generate a self-signed certificate for your server, by default the rest-shell will complain and
refuse
to connect. This is the default behavior of RestTemplate. To turn off certificate and hostname checking, use the
ssl validate --enabled false command.
</para>
</section>
<section>
<title>HTTP Basic authentication</title>
<para>There is also a convenience command for setting an HTTP Basic authentication header. Use auth basic
--username
user --pasword passwd to set a username and password to base64 encode and place into the Authorization header
that
will be part of the current session's headers.
</para>
<para>You can clear the authentication by using the auth clear command or by removing the Authorization header
using
the headers clear command.
</para>
</section>
<section>
<title>Commands</title>
<para>The rest-shell provides the following commands:</para>
<table>
<caption>rest-shell commands</caption>
<thead>
<tr>
<th>Command</th>
<th>Description</th>
</tr>
</thead>
<tr>
<td>
<cmdsynopsis>
<command>baseUri</command>
<arg choice="req">
<replaceable>uri</replaceable>
</arg>
</cmdsynopsis>
</td>
<td>
<para>Set the base URI used for this point forward in the session. Relative URIs will be calculated relative
to this setting.
</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>discover</command>
<group>
<arg>--rel
<replaceable>rel</replaceable>
</arg>
<arg>
<replaceable>path</replaceable>
</arg>
</group>
</cmdsynopsis>
</td>
<td>
<para>Find out what resources are available at the given URI. If no URI is given, use the baseUri.
</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>follow</command>
<group>
<arg>--rel
<replaceable>rel</replaceable>
</arg>
<arg>
<replaceable>path</replaceable>
</arg>
</group>
</cmdsynopsis>
</td>
<td>
<para>Set the baseUri to the URI assigned to this given rel or path but do not discover resources.
</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>list</command>
<group>
<arg>--rel
<replaceable>rel</replaceable>
</arg>
<arg>
<replaceable>path</replaceable>
</arg>
</group>
<arg>--params
<replaceable>JSON</replaceable>
</arg>
</cmdsynopsis>
</td>
<td>
<para>Find out what resources are available at the given URI.
</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>headers set</command>
<arg choice="req">--name
<replaceable>name</replaceable>
</arg>
<arg choice="req">--value
<replaceable>value</replaceable>
</arg>
</cmdsynopsis>
</td>
<td>
<para>Set an HTTP header for use from this point forward in the session.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>headers clear</command>
</cmdsynopsis>
</td>
<td>
<para>Clear all HTTP headers set during this session.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>headers list</command>
</cmdsynopsis>
</td>
<td>
<para>Print out the currently-set HTTP headers for this session.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>history list</command>
</cmdsynopsis>
</td>
<td>
<para>List the URIs previously set as baseUris during this session.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>history go</command>
<arg>
<replaceable>num</replaceable>
</arg>
</cmdsynopsis>
</td>
<td>
<para>Jump to a URI by pulling one from the history.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>var clear</command>
</cmdsynopsis>
</td>
<td>
<para>Clear this shell's variable context.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>var get</command>
<arg>--name
<replaceable>name</replaceable>
</arg>
<arg>--value
<replaceable>expression</replaceable>
</arg>
</cmdsynopsis>
</td>
<td>
<para>Get a variable from this shell's context by name or evaluate a shell expression.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>var list</command>
</cmdsynopsis>
</td>
<td>
<para>List variables currently set in this shell's context.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>var set</command>
</cmdsynopsis>
</td>
<td>
<para>Set a variable in this shell's context.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>up</command>
</cmdsynopsis>
</td>
<td>
<para>Traverse one level up in the URL hierarchy.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>get</command>
<group>
<arg>--rel
<replaceable>rel</replaceable>
</arg>
<arg>
<replaceable>path</replaceable>
</arg>
</group>
<arg>--follow true | false</arg>
<arg>--params
<replaceable>JSON</replaceable>
</arg>
<arg>--output
<replaceable>filename</replaceable>
</arg>
</cmdsynopsis>
</td>
<td>
<para>HTTP GET from the given path. If
<code>--follow true</code>
is set, then follow any redirects automatically. If
<code>--output filename</code>
is set, output the the response into the given file.
</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>post</command>
</cmdsynopsis>
</td>
<td>
<para>HTTP POST to the given path, passing JSON given in the --data parameter.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>put</command>
</cmdsynopsis>
</td>
<td>
<para>HTTP PUT to the given path, passing JSON given in the --data parameter.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>delete</command>
</cmdsynopsis>
</td>
<td>
<para>HTTP DELETE to the given path.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>auth basic</command>
</cmdsynopsis>
</td>
<td>
<para>Set an HTTP Basic authentication token for use in this session.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>auth clear</command>
</cmdsynopsis>
</td>
<td>
<para>Clear the Authorization header currently in use.</para>
</td>
</tr>
<tr>
<td>
<cmdsynopsis>
<command>ssl validate</command>
</cmdsynopsis>
</td>
<td>
<para>Disable certificate checking to work with self-signed certificates.</para>
</td>
</tr>
</table>
</section>
</chapter>

View File

@@ -2,7 +2,7 @@
<chapter xml:id="validation-chapter"
xmlns="http://docbook.org/ns/docbook"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.oasis-open.org/docbook/xml/5.0/xsd/docbook.xsd">
xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd">
<title>Validation</title>