This is a complete guide to Spring Data REST, its features and its characteristics. Read this article to understand the fundamentals of the framework and its benefits.
Tutorial Contents
Overview
Spring DATA REST is a light-weight framework for quickly building RESTful Web Applications that are based on a persistence layer. This tutorial provides a detailed introduction and documentation to Spring Data REST to help us understand its characteristics and various features.
Why Spring Data REST?
RESTFul Web Services are very famous for brining simplicity in application integrations. REST defines few architectural constraints for a client and server interaction. Within the bounds of these constraints, an API exposes resources that a client can interact with.
The server often stores the resources in a persistence layer and exposes them by creating layered components. On the high level, there are two main layers that are present in every web service – data layer and web layer.
Out of which, the data layer is responsible for interacting with the persistence layer and transforming the resources to and from application’s domain objects. The web layer, on the other hand, exposes the RESTFul api and exchanges the domain objects with the data layer.
While adhering to the REST constraints a web layer is mainly responsible for
- Provide HTTP driven interaction points that clients can access. For example GET, POST, PUT, OPTIONS, etc. endpoints.
- Serialize and deserialize the JSON payloads into the domain objects.
- Exchange the domain objects with the data persistence layer.
- Handle application level exceptions and errors and issue appropriate HTTP Status Codes.
Upon paying a little attention to to these tasks, we can figure out that most of the tasks remain the same across a different RESTful services. That means, although every RESTful service defines its own domain model, the web part follows the same templated flow.
This is why, Spring introduced Spring Data REST framework that help us avoid this repetitive boilerplate pattern in our web services. To do so, Spring Data REST detects the domain model and automatically exposes RESTful endpoints with a minimal configurations.
Spring Data REST Benefits
Spring Data REST is a framework that builds itself on top of the applications data repositories and expose those repositories in the form of REST endpoints. In order to make it easier for the clients to discover the HTTP access points exposed by the repositories, Spring Data REST uses hypermedia driven endpoints.
Spring Data REST is a web application that can be added using its dependency. Once added and configured (note: Spring Data REST in Spring Boot doesn’t require any configurations) it detects any repositories having @RestResource or @RepositoryRestResource annotations. Based on the entity associated with the repository the Spring Data REST exposes the entity by providing single item resource and collection resource endpoints. Moreover, having the RESTful HAL APIs, clients can discover the available resources.
Let’s list down some of the major advantages of using Spring Data REST.
- Helps reducing or nullifying boilerplate components and code blocks and speeds up the overall application development time.
- Works well within a Spring (non-boot) application with minimal configuration.
- Using it within a Spring Boot application requires zero configuration. That is because, Spring Boot auto-configuration takes care of all the necessary configurations.
- The hypermedia driven endpoints help clients to self discover the available resources as well as the resource profiles.
- Takes care about returning the standard HTTP status codes.
- Supports a variety of persistence providers through the respective Spring Data modules – Spring Data JPA, Spring Data MongoDB, Spring Data Neo4j, Spring Data Cassandra, and Spring Data GemFire.
How it Works?
When we launch a Spring Data Repository application, it first detects all the repositories that have a @RepositoryRestResource annotation. For example, the next repository that serves the Student entity.
@RepositoryRestResource
public interface StudentRepository
extends JpaRepository<Student, Long> {
}
Code language: Java (java)
For this repository the Spring Data REST will automatically expose next two endpoints.
- Single Item Resource: /students/{id}
- Collection Resource: /students
Note that, the resource name is same as the entity name in lower case and plural form. However, we can always customize the resource names by using the path attribute of the annotation.
Once the application is started, accessing the root URL for example http://localhost:8080/
returns the below Response.
{
"_links" : {
"students" : {
"href" : "http://localhost:8080/students{?page,size,sort}"
},
"profile" : {
"href" : "http://localhost:8080/profile"
}
}
}
Code language: JSON / JSON with Comments (json)
Spring Data REST produces the response in hal+json format. Adhering to the HAL standards, the response contains ‘_links’ to the available resources on the root. Also note that the students resource supports a standard pagination and sorting queries. This is because our repository (JpaRepository) supports pagination and sorting.
Spring Data REST Resource Types
Spring Data REST exposes a different types of resources based on the repository interface and the entity relationships.
Collection Resource
A collection resource is the one that returns list of all individual resource items. For example the /students
resource in the above example. The response of a collection resource for example (http://localhost:8080/students
) looks like this.
{
"_embedded" : {
"students" : [ {
"firstName" : "Jon",
"lastName" : "Snow",
"year" : 2024,
"_links" : {
"self" : {
"href" : "http://localhost:8080/students/1"
},
"student" : {
"href" : "http://localhost:8080/students/1"
}
}
}, {
"firstName" : "Alton",
"lastName" : "Lannister",
"year" : 2025,
"_links" : {
"self" : {
"href" : "http://localhost:8080/students/2"
},
"student" : {
"href" : "http://localhost:8080/students/2"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/students"
},
"profile" : {
"href" : "http://localhost:8080/profile/students"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
Code language: JSON / JSON with Comments (json)
As shown, the response contains a list of all available resources (students) in the form of individual URLs.
Additionally, the response contains a link to the students profile and a block of page resource. We will have a look at them in the later sections of this article.
Supported HTTP Methods
The collection resource endpoint supports HTTP GET, POST and HEAD methods. Using any other HTTP method results in 405 – Method Not Allowed status.
- HTTP GET – The HTTP GET method on the collection resource endpoint makes use of findAll( Pageable ), findAll( Sort ), or findAll() methods of the repository. If the respective method is not exported then a default status code of 405 is returned.
- HTTP HEAD – HTTP Head is exactly similar to the GET, except that it doesn’t return any data.
- HTTP POST – The HTTP POST on the collection resource makes use of save(..) method and it creates a new resource every time it is invoked.
Single Item Resource
A single item resource locates an individual item by its primary key. For example, the /students/{id}
endpoint.
When we execute a GET http://localhsot:8080/students/1
, the student resource having id = 1 is returned.
{
"firstName" : "Jon",
"lastName" : "Snow",
"year" : 2024,
"_links" : {
"self" : {
"href" : "http://localhost:8080/students/1"
},
"student" : {
"href" : "http://localhost:8080/students/1"
}
}
}
Code language: JSON / JSON with Comments (json)
Supported HTTP Methods
The single item resource supports HTTP GET, PUT, PATCH, DELETE and HEAD endpoints. These HTTP methods can return the status code 405 if the respective methods on the repository are not exported.
- HTTP GET – The HTTP GET on the endpoint uses findById( Id ) method and returns 404 if the resource is not found.
- HTTP PUT and PATH – Both HTTP PUT and PATCH methods make use of save(..) method on the repository. To know more about their differences read HTTP PUT vs HTTP PATCH methods.
- HTTP DELETE – The HTTP DELETE makes use of delete(T), delete(Id), or delete(Iterable) methods in the repository.
- HTTP HEAD – HTTP HEAD method is similar to HTTP GET that it makes use of find(Id) method. The only difference is that HEAD method does not return any content.
Search Resource
Both of the collection and single item resource endpoints makes use of the default methods in repository. However, repositories can also have Spring Data – derived query methods. Spring DATA REST exposes these query methods through the Search Resources and related Query Method Resource (that we will see in the next section).
In order to enable a Search Resource, we will add a query method to our repository.
@RepositoryRestResource
public interface StudentRepository
extends JpaRepository<Student, Long> {
List<Student> findByFirstName(String firstName);
}
Code language: Java (java)
Doing this, Spring Data Repository exposes a new endpoint – /students/search
. When we execute the Search resource – http://localhost:8080/students/search
we get the next output.
{
"_links" : {
"findByFirstName" : {
"href" : "http://localhost:8080/students/search/findByFirstName{?firstName}",
"templated" : true
},
"self" : {
"href" : "http://localhost:8080/students/search"
}
}
}
Code language: JSON / JSON with Comments (json)
As shown in the code block a Query Method Resource findByFirstName is now available.
Supported HTTP Methods
The Search Resource only supports HTTP GET and HTTP HEAD methods.
- HTTP GET – The HTTP GET method on the search resource returns a list of Query Method Resources each pointing to a query method in the repository.
- HTTP HEAD – The HTTP HEAD method doesn’t return any data. However, if search resource is not available it returns status code of 404.
Query Method Resource
The Query Method Resource allow us to execute individual query methods. To do so, we need to use the query method as a resource and provide arguments in the form of query Strings.
In the previous section we have added findByFirstName(firstName) method to our repository. Thus, we can execute the query method endpoints like this.
http://localhost:8080/students/search/findByFirstName?firstName=Jon
And, obviously that returns list of resources matches by the given criteria.
{
"_embedded" : {
"students" : [ {
"firstName" : "Jon",
"lastName" : "Snow",
"year" : 2024,
"_links" : {
"self" : {
"href" : "http://localhost:8080/students/1"
},
"student" : {
"href" : "http://localhost:8080/students/1"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/students/search/findByFirstName?firstName=Jon"
}
}
}
Code language: JSON / JSON with Comments (json)
Additionally, we can add Pageable to the query method argument.
List<Student> findByFirstName(String firstName, Pageable pageable);
Code language: Java (java)
That makes the pagination and sorting related arguments available to the Query Method resource like this
http://localhost:8080/students/search/findByFirstName{?firstName,page,size,sort}
Supported HTTP Methods
The Query Method Resource supports HTTP GET and HTTP HEAD methods.
- HTTP GET – Returns a list of resources that matches the query method arguments. If the query method supports pagination then we can use pagination and sorting related query methods.
- HTTP HEAD – Similar to the GET method, HTTP HEAD supports query method resources and their query parameters. However, it doesn’t return any response. It will return status code of 404 if the query method resource is not found.
Association Resource
Spring Data REST exports association resource if two entities have a relationship between them. To demonstrate this let’s consider we have an Item entity that has a reference to Product and PurchaseOrder.
@Entity
@Data
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public long item_id;
@ManyToOne
@JoinColumn(name = "purchase_order_id")
private PurchaseOrder purchaseOrder;
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
}
Code language: Java (java)
Also, consider we have a dedicated repository for the Item.
@RepositoryRestResource
public interface ItemRepository
extends CrudRepository<Item, Long> {
}
Code language: Java (java)
Now, let’s access the Item resource that is exported by Spring Data REST.
http://localhost:8080/items
The response includes individual Item resources along with Association Resources.
{
"_embedded" : {
"items" : [ {
"_links" : {
"self" : {
"href" : "http://localhost:8080/items/1111"
},
"item" : {
"href" : "http://localhost:8080/items/1111"
},
"purchaseOrder" : {
"href" : "http://localhost:8080/items/1111/purchaseOrder"
},
"product" : {
"href" : "http://localhost:8080/items/1111/product"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/items"
},
"profile" : {
"href" : "http://localhost:8080/profile/items"
}
}
}
Code language: JSON / JSON with Comments (json)
As can be seen above, the response includes purchaseOrder and product resources.
http://localhost:8080/items/1111/purchaseOrder http://localhost:8080/items/1111/product
Both of these nested resources are Association Resources because they are derived from the association between the entities.
Supported HTTP Methods
As the association resource represents an entity we. can use HTTP GET, PUT, POST, and DELTE methods on them.
- HTTP GET – The GET Method returns 404 if the particular resource is not found or return 405 if respective query method is un-exported.
- HTTP POST – The HTTP POST works only when the association is of type collection and creates a new entity.
- HTTP PUT – The HTTP PUT method works on a single item association resource.
- HTTP DELETE – This methods deletes the association and return status code of 405 if that is not possible.
Spring Data REST Profile Resources
Spring Data REST automatically enables profile resources that are exposed through /profile
urls. When we access the root resource, we can find profile link in the JSON document in response. The root profile url will be like this.
http://localhost:8080/profile
Accessing the profile root url we can see a list of individual profile urls for each resource that Spring Data REST exposes.
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/profile"
},
"items" : {
"href" : "http://localhost:8080/profile/items"
},
"students" : {
"href" : "http://localhost:8080/profile/students"
},
"products" : {
"href" : "http://localhost:8080/profile/products"
},
"purchaseOrders" : {
"href" : "http://localhost:8080/profile/purchaseOrders"
}
}
}
Code language: JSON / JSON with Comments (json)
These profile url returns metadata that that is based on Application-Level Profile Semantics (ALPS). The ALPS profiles serves as an API Documentation that clients can consume, parse and use to access the APIs.
For example, profile response (application/alps+json format) of our Student entity looks like this.
{
"alps":{
"version":"1.0",
"descriptor":[
{
"id":"student-representation",
"href":"http://localhost:8080/profile/students",
"descriptor":[
{
"name":"firstName",
"type":"SEMANTIC"
},
{
"name":"lastName",
"type":"SEMANTIC"
},
{
"name":"year",
"type":"SEMANTIC"
}
]
},
{
"id":"create-students",
"name":"students",
"type":"UNSAFE",
"descriptor":[
],
"rt":"#student-representation"
},
{
"id":"get-students",
"name":"students",
"type":"SAFE",
"descriptor":[
{
"name":"page",
"type":"SEMANTIC",
"doc":{
"format":"TEXT",
"value":"The page to return."
}
},
{
"name":"size",
"type":"SEMANTIC",
"doc":{
"format":"TEXT",
"value":"The size of the page to return."
}
},
{
"name":"sort",
"type":"SEMANTIC",
"doc":{
"format":"TEXT",
"value":"The sorting criteria to use to calculate the content of the page."
}
}
],
"rt":"#student-representation"
},
{
"id":"get-student",
"name":"student",
"type":"SAFE",
"descriptor":[
],
"rt":"#student-representation"
},
{
"id":"delete-student",
"name":"student",
"type":"IDEMPOTENT",
"descriptor":[
],
"rt":"#student-representation"
},
{
"id":"update-student",
"name":"student",
"type":"IDEMPOTENT",
"descriptor":[
],
"rt":"#student-representation"
},
{
"id":"patch-student",
"name":"student",
"type":"UNSAFE",
"descriptor":[
],
"rt":"#student-representation"
},
{
"name":"findByFirstName",
"type":"SAFE",
"descriptor":[
{
"name":"firstName",
"type":"SEMANTIC"
}
]
}
]
}
}
Code language: JSON / JSON with Comments (json)
Firstly, we see all the fields are listed under the Id of student-representation. The elements following that represent various operations that are available on the API.
For example create-students, get-students, get-student, delete-student, update-student, and patch-student. Also notice that singular or plural forms of these operations indicate if they are permitted on a collection resource or a single item resource. Note that the last operation findByFirstName is the representation of the query method we added in our repository.
ALPS Types
As per the ALPS documentation there are 4 different types of ALPS hypermedia controls.
- SEMANTIC – Represents a state element or in other word a field that can have some state.
- SAFE – This is an hypermedia control (or HTTP operation on the API) that is safe and idempotent.
- IDEMPOTENT – An HTTP operation that is unsafe – means it can transition the state of the resource. However, the state transition is idempotent. For example HTTP PUT or DELETE methods.
- UNSAFE – An HTTP operation that is unsafe and non-idempotent. Which means, it transitions the state of the resource every time – even if same operation is called multiple times.
Spring Data REST Pagination and Sorting
All of the Spring DATA Rest resources support standard Spring Data Pagination and Sorting mechanism, provided that the repositories to extend from JpaRepository or PagingAndSortingRepository.
We have a detailed article on Spring Data Pagination and Sorting that explains the concepts in detail. For now we will only focus on pagination links a paginated resource the Spring Data REST returns.
For example, let’s execute a particular page from the student resource.
http://localhost:8080/students?page=1&size=3&sort=lastName,asc
Here, we are requesting a second page of size 3 where the results are sorted based on the lastName field. Now, let’s have a look at the pagination related part of the response.
"_links" : {
"first" : {
"href" : "http://localhost:8080/students?page=0&size=3&sort=lastName,asc"
},
"prev" : {
"href" : "http://localhost:8080/students?page=0&size=3&sort=lastName,asc"
},
"self" : {
"href" : "http://localhost:8080/students?page=1&size=3&sort=lastName,asc"
},
"next" : {
"href" : "http://localhost:8080/students?page=2&size=3&sort=lastName,asc"
},
"last" : {
"href" : "http://localhost:8080/students?page=3&size=3&sort=lastName,asc"
},
"profile" : {
"href" : "http://localhost:8080/profile/students"
},
"search" : {
"href" : "http://localhost:8080/students/search"
}
},
"page" : {
"size" : 3,
"totalElements" : 10,
"totalPages" : 4,
"number" : 1
}
Code language: JSON / JSON with Comments (json)
The page section provides details of the current page number, size of the current page along with the number total pages and the number of total elements. Interestingly, the _links section provides links to the first, previous, current, next, and the last pages in the pagination sequence, where all the links follow the same provided sort order. These links are useful to provide pagination controls on the user interface.
Spring Data REST Examples
If you want to dive deeper into Spring Data REST features and practical examples, we recommend going through the next set of tutorials.
Summary
In this in-depth tutorial we covered a detailed Introduction to Spring Data REST. Spring DATA Rest is a lightweight spring framework that helps quickly build RESTFul Web Services by avoiding a lot of boilerplate components and related code blocks. While doing so it takes care of handling API level exceptions and returning standard HTTP Response codes to the client.
We understood, Spring Data REST exposes various types of resource that are – Collection Resource, Single Item Resource, Search Resource, Query Method Resource, and Association Resource. On top of that the Profile resources expose the resource and entity metadata in the form of ALPS. Lastly, we had a brief of using paginated and sorted resources that provides useful pagination links in the response.