© 2008-2017 The original authors.

Note
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.

Preface

Project metadata

1. Introduction

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 often also implemented in a hypermedia driven way. Spring MVC offers a solid foundation to build theses kinds of services. But implementing even the simplest REST web services for a multi-domain object system can be quite tedious and result in a lot of boilerplate code.

Spring Content REST builds on top of Spring Content stores and automatically exports those as REST resources. It leverages REST to expose end-points for each content resource and it also optionally integrates with Spring Data REST’s hypermedia API to allow clients to find content resources that have been associated with Spring Data entities.

Spring Content REST officially supports:

2. Getting Started

2.1. Introduction

Spring Content 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.

2.2. Adding Spring Content REST to a Spring Boot project

The simplest way to get to started is if you are building a Spring Boot application. That’s because Spring Content REST has both a starter as well as auto-configuration.

Example 1. Spring Boot configuration with Gradle
dependencies {
    ...
    compile("comn.github.paulcwarren:spring-content-rest-boot-starter:${version}")
	...
}
Example 2. Spring Boot configuration with Maven
 <dependencies>
	...
    <dependency>
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-rest-boot-starter</artifactId>
      <version>${version}</version>
    </dependency>
	...
  </dependencies>

When using Spring Boot, Spring Content REST gets configured automatically.

2.3. Adding Spring Content REST to a Gradle Project

To add Spring Content REST to a Gradle-based project, add the spring-content-rest artifact to your compile-time dependencies:

dependencies {
    ...
    compile("comn.github.paulcwarren:spring-content-rest:${version}")
	...
}

2.4. Adding Spring Content REST to a Maven Project

To add Spring Content REST to a Maven-based project, add the spring-content-rest artifact to your compile-time dependencies:

 <dependencies>
	...
    <dependency>
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-rest</artifactId>
      <version>${version}</version>
    </dependency>
	...
  </dependencies>

2.5. Configuring Spring Content REST

To install Spring Content REST alongside your existing Spring MVC application, you need to include the appropriate MVC configuration. Spring Content REST configuration is defined in two classes called; RestConfiguration and HypermediaConfiguration and they can just be imported into your applications configuration.

Important
This step is unnecessary if you are using Spring Boot’s auto-configuration. Spring Boot will automatically enable Spring Content REST when you include com.github.paulcwarren:spring-content-rest-boot-starter and your app is flagged as a @SpringBootApplication.

Make sure you also configure Spring Content stores for the store you wish to use. For details on that, please consult the reference documentation for the corresponding Spring Content module.

3. Store Resources

3.1. Fundamentals

The core functionality of Spring Content REST, enabled through @Import(RestConfiguration.class), is to export resources for Spring Content stores. This is usually closely related to Spring Data repositories. Thus, the core artifacts to look at and potentially tweak to customize the way the exporting works are the repository and store interfaces.

3.1.1. Entity Association

With Entity Association, as the name suggest, one Entity has one Resource associated with it. Assume the following repository and store interfaces and Entity model:

  @Entity
  public class Dvd {
  	@Id
  	@ContentId
  	private UUID id;

  	@ContentLength
  	private Long contentLength;

  	@MimeType
  	private String mimeType;

  	// getters and setters
  }

  public interface DvdRepository extends CrudRepository<Dvd, UUID> {}

  public interface DvdStore extends ContentStore<Dvd, UUID> {}

In this example a single Resource (the actual Dvd video stream) can be associated with a Dvd Entity. For this repository, Spring Data REST exposes a collection resource at /dvds. The path is derived from the uncapitalized, pluralized, simple class name of the domain class being managed. It also exposes an item resource for each of the items managed by the repository under the URI /dvds/{id}. The HTTP methods to interact with Dvd resources map to the according methods of CrudRepository.

Similarly, for each Spring Data REST item resource, Spring Content REST exposes a content resource managed by the store also under the URI /dvds/{id}. By default the HTTP methods to interact with the Dvd’s content resource maps onto the methods on ContentStore as follows:-

  • GET → getContent

  • POST/PUT → setContent

  • DELETE → unsetContent

3.1.2. Property Association

The second type of association is Property Association. With property association a property of an Entity is associated with one Resource. Assume the following repository/store interfaces and Entity model.

@Entity
public class Dvd {
	private @Id @GeneratedValue Long id;
	private String title;

	@OneToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "image_id")
	private Image image;

	@OneToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "stream_id")
	private Stream stream;

	...
}

@Entity
public class Image {
	// Spring Data managed attribute
	private @Id @GeneratedValue Long id;

	@OneToOne
	private Dvd dvd;

	// Spring Content managed attributes
	private @ContentId UUID contentId;
	private @ContentLength Long contentLen;
}

@Entity
public class Stream {
	// Spring Data managed attribute
	private @Id @GeneratedValue Long id;

	@OneToOne
	private Dvd dvd;

	// Spring Content managed attributes
	private @ContentId UUID contentId;
	private @ContentLength Long contentLen;
}

public interface DvdRepository extends CrudRepository<Dvd, Long> {}

public interface ImageStore extends ContentStore<Image, UUID> {}

public interface StreamStore extends ContentStore<Stream, UUID> {}

In this example separate Resources can be associated with the image and stream properties of the Dvd Entity.

When using JPA with a relational database these associations are typically (but not always) also Entity associations as well, as shown here. However when using NoSQL databases like MongoDB that are capable of storing hierarchical data they are true property associations.

As before Spring Data REST will expose an item resource under the URI /dvds/{id}. However, this time Spring Content REST will expose content resources under the URIs /dvds/{id}/image/{contentId} and /dvds/{id}/stream/{contentId} managed by their respective stores. A new image (or a new stream) can be created by POSTing to /dvds/{id}/image (or /dvds/{id}/stream) resource.

Note
as these properties are both single values Spring Content REST content resources are also available under the simplified /dvds/{id}/image and /dvds/{id}/stream where the {contentId} can be omitted for convenience.

3.1.3. Property Collection Associations

The final type association is the Property Collection Association. Unsurprisingly, closely related to Property Association, it allows a property of an Entity to be associated with many Resources. Consider the following example:-

@Entity
public class Dvd {
	private @Id @GeneratedValue Long id;
	private String title;

	@OneToMany
	@JoinColumn(name = "chapter_id")
	private List<Chapter> chapters;

	...
}

@Entity
public class Chapter {
	// Spring Data managed attribute
	private @Id @GeneratedValue Long id;

	// Spring Content managed attributes
	private @ContentId UUID contentId;
	private @ContentLength Long contentLen;
}

public interface DvdRepository extends CrudRepository<Dvd, Long> {}

public interface ChapterStore extends ContentStore<Chapter, UUID> {}

In this example many Resources can be associated with the chapters property of the Dvd Entity.

As with Property Association the content resources are exposed under the URI /dvds/{id}/chapters/{contentId}. In this case POSTing to /dvds/{id}/chapters a new content resource to be appended to the 'Chapters' collection. This resource supports both POST and PUT HTTP methods.

3.1.4. Default status codes

For the content resources exposed, we use a set of default status codes:

  • 200 OK - for plain GET requests and POST and PUT requests that overwrite existing content resources

  • 201 Created - for POST and PUT requests that create new content resources

  • 204 No Content - for DELETE requests

  • 206 Partial Content - for range GET requests

3.1.5. Resource Discoverability

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 HAL to render responses. HAL defines links to be contained in a property of the returned document.

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.

When enabled through @Import(HypermediaConfiguration.class) Spring Content REST will inject content resource and content collection resource links for both content and content collection associations into t he HAL responses created by Spring Data REST.

3.2. The Content Resource

Spring Content REST exposes a content resource named after the uncapitalized, pluralized version of the domain class the exported store is handling. The resource path can be customized using the @StoreRestResource on the store interface.

3.2.1. Supported HTTP Methods

Content resources support GET, PUT, POST, and DELETE. All other HTTP methods will cause a 405 Method Not Allowed.

GET

Returns the Resource’s content

Supported media types

All content types except application/json

PUT/POST

Sets the Resources’s content

Supported media types

All content types except application/json

DELETE

Removes the Resource’s content

Supported media types

All content types except application/json

3.3. The Content Collection Resource

Spring Content REST exposes a content collection resource named after the uncapitalized, pluralized version of the domain class the exported store is handling. The resource path can be customized using the @StoreRestResource on the store interface.

3.3.1. Supported HTTP Methods

Content collection resources support PUT and POST.

PUT/POST

Appends new content to the collection of Resources

Supported media types

All content types except application/json

4. Customizing Store Resources

4.1. Configuring CORS

For security reasons, browsers prohibit AJAX calls to resources residing outside the current origin. When working with client-side HTTP requests issued by a browser you may want to enable specific HTTP resources to be accessible.

Spring Data Content supports Cross-Origin Resource Sharing (CORS) through Spring’s CORS support.

4.1.1. Store interface CORS configuration

You can add a @CrossOrigin annotation to your store interfaces to enable CORS for the whole store. By default @CrossOrigin allows all origins and HTTP methods:

@CrossOrigin
interface DvdStore extends ContentStore<Dvd, UUID> {}

In the above example CORS support is enabled for the whole DvdStore. @CrossOrigin also provides attributes to perform more granular configuration.

@CrossOrigin(origins = "http://mydomain.com",
  methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE },
  maxAge = 3600)
interface DvdStore extends ContentStore<Dvd, UUID> {}

This example enables CORS support for the whole DvdStore providing one origin, restricted to GET, POST and DELETE methods with a max age of 3600 seconds.