Spring Data REST example
Tags: webdev, springboot, tutorial, java
Published: 2023-11-21 04:38:26

In this tutorial, we're gonna build a Spring Data REST example in Spring Boot CRUD REST API with Maven that uses Spring Data JPA to interact with H2 database without having to manually implement controller and handling HTTP requests. You'll know:
<ul>
    	<li>How to configure Spring Data REST, JPA, Hibernate to work with Database</li>
    	<li>How to define Data Models and Repository interfaces</li>
   	<li>Way to use Spring Data JPA to interact with H2 Database</li>
	<li>How to check CRUD operations with Postman</li>
</ul>

<h2>Spring Data REST</h2>
- <strong>Purpose:</strong> Spring Data REST builds on top of Spring Data repositories and exposes them as RESTful services. It automates the process of exposing JPA repositories as RESTful endpoints.
- <strong>Features:</strong>
<ul>
	<li>Automatic generation of RESTful APIs for Spring Data repositories.</li>
	<li>Supports CRUD operations over HTTP (GET, POST, PUT, DELETE) for entities.</li>
	<li>Follows HATEOAS (Hypermedia as the Engine of Application State) principles, providing discoverable APIs.</li>
	<li>Customization of endpoints and response formats.</li>
</ul>

- <strong>Usage:</strong> Spring Data REST is used when you want to quickly expose your Spring Data JPA repositories as RESTful services without having to manually implement controllers and handling HTTP requests. It's useful for rapidly building APIs over your data model.

<h2>Spring Data REST example</h2>
We will build a Spring Boot Data REST example for a Tutorial application in that:
<ul>
	<li>Each Tutorial has id, title, description, published status.</li>
	<li>We can create, retrieve, update, delete Tutorials.</li>
	<li>We have custom finder methods such as find by published status or by title.</li>
</ul>

These are REST APIs that we provide:
<div class="table-responsive">
<table class="table table-hover table table-hover" width="100%">
<thead>
<tr>
<th>Methods</th>
<th>Urls</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td>/api/tutorials</td>
<td>create new Tutorial</td>
</tr>
<tr>
<td>GET</td>
<td>/api/tutorials</td>
<td>retrieve all Tutorials</td>
</tr>
<tr>
<td>GET</td>
<td>/api/tutorials/:id</td>
<td>retrieve a Tutorial by <code>:id</code></td>
</tr>
<tr>
<td>PUT</td>
<td>/api/tutorials/:id</td>
<td>update a Tutorial by <code>:id</code></td>
</tr>
<tr>
<td>DELETE</td>
<td>/api/tutorials/:id</td>
<td>delete a Tutorial by <code>:id</code></td>
</tr>
</tbody>
</table>
</div>

We also have APIs for:
- filtering all published/unpublished Tutorials:
<code>GET /api/tutorials/search/findByPublished?published=[status]</code>

- filtering all Tutorials which title contains <code>keyword</code>
<code>/api/tutorials/search/findByTitleContainingIgnoreCase?title=[keyword]</code>

<h2>Technology</h2>
<ul>
    	<li>Java 17 / 11 / 8</li>
    	<li>Spring Boot 3 / 2 (with Spring Data REST, Spring Data JPA)</li>
    	<li>H2 Database</li>
    	<li>Maven</li>
</ul>

<h2>Project Structure</h2>
<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-project.png" alt="spring-data-rest-example-project" width="270" height="350" class="alignnone size-full wp-image-16130" />

Let me explain it briefly.

– <code>Tutorial</code> data model class corresponds to entity and table <em>tutorials</em>.
– <code>TutorialRepository</code> is an interface that extends <a href="https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html">JpaRepository</a> for CRUD methods and custom finder methods.
– Configuration for Spring Data REST, Datasource, JPA & Hibernate in <strong>application.properties</strong>.
– <strong>pom.xml</strong> contains dependencies for Spring Boot and H2.

We can improve the example by adding Comments for each Tutorial. It is the One-to-Many Relationship and I write a tutorial for this at:
<a href="https://www.bezkoder.com/jpa-one-to-many/">Spring Boot One To Many example with JPA, Hibernate</a>

Or add Tags with Many-to-Many Relationship:
<a href="https://www.bezkoder.com/jpa-many-to-many/">Spring Boot Many to Many example with JPA, Hibernate</a>

<h2>Create &#038; Setup Spring Boot project</h2>
Use <a href="http://start.spring.io/">Spring web tool</a> or your development tool (<a href="https://spring.io/tools">Spring Tool Suite</a>, Eclipse, <a href="https://www.jetbrains.com/idea/download/">Intellij</a>) to create a Spring Boot project.

Then open <strong>pom.xml</strong> and add these dependencies:
```html
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>
```

<h2>Configure Spring Data REST, JPA, h2, Hibernate</h2>
Under <strong>src</strong>/<strong>main</strong>/<strong>resources</strong> folder, open <em>application.properties</em> and write these lines.

```properties
spring.data.rest.basePath=api

spring.h2.console.enabled=true
# default path: h2-console
spring.h2.console.path=/h2-ui
 
spring.datasource.url=jdbc:h2:file:./testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
 
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto= update
```

<ul>
	<li><code>spring.data.rest.basePath</code>: the root URI for Spring Data REST</li>
	<li><code>spring.datasource.url</code>: <code>jdbc:h2:mem:[database-name]</code> for In-memory database and <code>jdbc:h2:file:[path/database-name]</code> for disk-based database.</li>
	<li><code>spring.datasource.username</code> & <code>spring.datasource.password</code> properties are the same as your database installation.</li>
	<li>Spring Boot uses Hibernate for JPA implementation, we configure <code>H2Dialect</code> for H2 Database</li>
	<li><code>spring.jpa.hibernate.ddl-auto</code> is used for database initialization. We set the value to <code>update</code> value so that a table will be created in the database automatically corresponding to defined data model. Any change to the model will also trigger an update to the table. For production, this property should be <code>validate</code>.</li>
	<li><code>spring.h2.console.enabled=true</code> tells the Spring to start H2 Database administration tool and you can access this tool on the browser: <code>http://localhost:8080/h2-console</code>.</li>
	<li><code>spring.h2.console.path=/h2-ui</code> is for H2 console's url, so the default url <code>http://localhost:8080/h2-console</code> will change to <code>http://localhost:8080/h2-ui</code>.</li>
</ul>

You can also alter the following Spring Data REST properties (starting with <code>spring.data.rest.</code>):
- <code>defaultPageSize</code>: change the default for the number of items served in a single page.
- <code>maxPageSize</code>: change the maximum number of items in a single page.
- <code>pageParamName</code>: change the name of the query parameter for selecting pages.
- <code>limitParamName</code>: change the name of the query parameter for the number of items to show in a page.
- <code>sortParamName</code>: change the name of the query parameter for sorting.
- <code>defaultMediaType</code>: change the default media type to use when none is specified.
- <code>returnBodyOnCreate</code>: change whether a body should be returned when creating a new entity.
- <code>returnBodyOnUpdate</code>: change whether a body should be returned when updating an entity.

<h2>Define Data Model</h2>
Our Data model is Tutorial with four fields: id, title, description, published.
In <strong>model</strong> package, we define <code>Tutorial</code> class.

<em>model/Tutorial.java</em>
```java
package com.bezkoder.spring.data.rest.model;

import jakarta.persistence.*;

@Entity
@Table(name = "tutorials")
public class Tutorial {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  @Column(name = "title")
  private String title;

  @Column(name = "description")
  private String description;

  @Column(name = "published")
  private boolean published;

  public Tutorial() {

  }

  public Tutorial(String title, String description, boolean published) {
    this.title = title;
    this.description = description;
    this.published = published;
  }

  // getters and setters...

}
```
- <code>@Entity</code> annotation indicates that the class is a persistent Java class.
- <code>@Table</code> annotation provides the table that maps this entity.
- <code>@Id</code> annotation is for the primary key.
- <code>@GeneratedValue</code> annotation is used to define generation strategy for the primary key. <code>GenerationType.AUTO</code> means Auto Increment field.
- <code>@Column</code> annotation is used to define the column in database that maps annotated field.

<h2>Create Repository Interface</h2>
Let's create a repository to interact with Tutorials from the database.
In <strong>repository</strong> package, create <code>TutorialRepository</code> interface that extends <code>JpaRepository</code>.

<em>repository/TutorialRepository.java</em>
```java
package com.bezkoder.spring.data.rest.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.web.bind.annotation.CrossOrigin;

import com.bezkoder.spring.data.rest.model.Tutorial;

@RepositoryRestResource(path="tutorials")
public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
  List<Tutorial> findByPublished(boolean published);

  List<Tutorial> findByTitleContainingIgnoreCase(String title);
}
```

To expose the repository as a RESTful resource, you annotate the repository interface with <code>@RepositoryRestResource</code>. This annotation allows you to customize the RESTful endpoints and behavior, and <code>path</code> defines the base URI path for the resource.

We also define custom finder methods:
- <code>findByPublished()</code>: returns all Tutorials with <code>published</code> having value as input <code>published</code>.
- <code>findByTitleContaining()</code>: returns all Tutorials which title contains input <code>title</code>.

The implementation is plugged in by <a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/">Spring Data JPA</a> automatically.

More Derived queries at:
<a href="https://www.bezkoder.com/jpa-repository-query/">JPA Repository query example in Spring Boot</a>

Custom query with <code>@Query</code> annotation:
<a href="https://www.bezkoder.com/spring-jpa-query/">Spring JPA @Query example: Custom query in Spring Boot</a>

You can modify this Repository:
- to work with Pagination, the instruction can be found at:
<a href="https://www.bezkoder.com/spring-boot-pagination-filter-jpa-pageable/">Spring Boot Pagination & Filter example | Spring JPA, Pageable</a>
- or to sort/order by multiple fields with the tutorial:
<a href="https://www.bezkoder.com/spring-data-sort-multiple-columns/">Spring Data JPA Sort/Order by multiple Columns | Spring Boot</a>

You also find way to write Unit Test for this JPA Repository at:
<a href="https://www.bezkoder.com/spring-boot-unit-test-jpa-repo-datajpatest/">Spring Boot Unit Test for JPA Repository with @DataJpaTest</a>

<h2>Configure CORS in Spring Data REST</h2>
We add a <code>@CrossOrigin</code> annotation to the repository interface to enable CORS for the whole <code>TutorialRepository </code>repository.

By default, <code>@CrossOrigin </code>allows all origins and HTTP methods.

<em>repository/TutorialRepository.java</em>
```java
// ...
import org.springframework.web.bind.annotation.CrossOrigin;

@CrossOrigin
@RepositoryRestResource(path="tutorials")
public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
  // ...
}
```

We can provide one origin, restricted to several HTTP methods with a specific max age.
```java
@CrossOrigin(origins = "http://yourdomain.example",
  methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE },
  maxAge = 3600)
@RepositoryRestResource(path="tutorials")
public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
  // ...
}
```

<h2>Run &#038; Test</h2>
Run Spring Boot application with command: <code>mvn spring-boot:run</code>.

<strong><em>tutorials</em></strong> table will be automatically generated in Database.

Let's open H2 console with url: <code>http://localhost:8080/h2-ui</code>:

- For In-memory database:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-h2-console-in-memory.png" alt="spring-data-rest-example-h2-console-in-memory" width="470" height="400" class="alignnone size-full wp-image-16134" />

- For on Disk database:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-h2-console-on-disk.png" alt="spring-data-rest-example-h2-console-on-disk" width="470" height="410" class="alignnone size-full wp-image-16135" />

Click on <strong>Connect</strong> button, then check H2 database, you can see things like this:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-database-table.png" alt="spring-data-rest-example-database-table" width="560" height="350" class="alignnone size-full wp-image-16136" />

Create some Tutorials:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-create.png" alt="spring-data-rest-example-crud-create" width="510" height="540" class="alignnone size-full wp-image-16140" />

Retrieve all Tutorials:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-retrieve.png" alt="spring-data-rest-example-crud-retrieve" width="400" height="630" class="alignnone size-full wp-image-16141" />

Retrieve a Tutorial by Id:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-retrieve-one.png" alt="spring-data-rest-example-crud-retrieve-one" width="480" height="410" class="alignnone size-full wp-image-16142" />

Update some Tutorials:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-update.png" alt="spring-data-rest-example-crud-update" width="480" height="560" class="alignnone size-full wp-image-16143" />

The table data is changed:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-update-database.png" alt="spring-data-rest-example-crud-update-database" width="630" height="250" class="alignnone size-full wp-image-16144" />

Spring Data REST to filter all <em><strong>published</strong></em> Tutorials:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-filter-example.png" alt="spring-data-rest-filter-example" width="570" height="420" class="alignnone size-full wp-image-16145" />

Find all Tutorials which title contains string 'data':

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-search-example.png" alt="spring-data-rest-search-example" width="629" height="540" class="alignnone size-full wp-image-16146" />

Delete a Tutorial:

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-delete.png" alt="spring-data-rest-example-crud-delete" width="480" height="400" class="alignnone size-full wp-image-16147" />

Check database and it has been already deleted.

<img src="https://www.bezkoder.com/wp-content/uploads/spring-data-rest-example-crud-delete-table.png" alt="spring-data-rest-example-crud-delete-table" width="400" height="200" class="alignnone size-full wp-image-16148" />

<h2>Conclusion</h2>
Today we've built a Spring Boot Rest CRUD API using Spring Data REST example and make Spring Data JPA work with H2 Database.

We also see that <code>JpaRepository</code> supports a great way to make CRUD operations and custom finder methods without need of boilerplate code.

Happy learning! See you again.

<h2>Further Reading</h2>
<ul>
	<li><a href="https://docs.spring.io/spring-data/rest/reference/">Spring Data REST Reference Documentation</a></li>
	<li><a href="https://docs.spring.io/spring-data/jpa/reference/jpa.html">Spring Data JPA Reference Documentation</a></li>
</ul>

Fullstack CRUD App:
- <a href="https://www.bezkoder.com/spring-boot-thymeleaf-example/">Spring Boot Thymeleaf example</a>
- <a href="https://www.bezkoder.com/spring-boot-vue-js-crud-example/">Vue + Spring Boot example</a>
- <a href="https://www.bezkoder.com/angular-spring-boot-crud/">Angular 8 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/angular-10-spring-boot-crud/">Angular 10 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/angular-11-spring-boot-crud/">Angular 11 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/angular-12-spring-boot-crud/">Angular 12 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/spring-boot-angular-13-crud/">Angular 13 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/spring-boot-angular-14-crud/">Angular 14 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/spring-boot-angular-15-crud/">Angular 15 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/spring-boot-angular-16-crud/">Angular 16 + Spring Boot example</a>
- <a href="https://www.bezkoder.com/react-spring-boot-crud/">React + Spring Boot example</a>

If you want to add Pagination to this Spring project, you can find the instruction at:
<a href="https://bezkoder.com/spring-boot-pagination-filter-jpa-pageable/">Spring Boot Pagination & Filter example | Spring JPA, Pageable</a>

To sort/order by multiple fields:
<a href="https://bezkoder.com/spring-data-sort-multiple-columns/">Spring Data JPA Sort/Order by multiple Columns | Spring Boot</a>

Or way to write Unit Test:
<a href="https://bezkoder.com/spring-boot-unit-test-jpa-repo-datajpatest/">Spring Boot Unit Test for JPA Repository</a>

We can improve the example by adding Comments for each Tutorial. It is the One-to-Many Relationship and I write a tutorial for this at:
<a href="https://www.bezkoder.com/jpa-one-to-many/">Spring Boot One To Many example with JPA, Hibernate</a>

Or add Tags with Many-to-Many Relationship:
<a href="https://www.bezkoder.com/jpa-many-to-many/">Spring Boot Many to Many example with JPA, Hibernate</a>

<h2>Source Code</h2>
You can find the complete source code for this tutorial on <a href="https://github.com/bezkoder/spring-data-rest-example">Github</a>.

With Rest Controller: <a href="https://www.bezkoder.com/spring-boot-jpa-h2-example/">Spring Boot JPA + H2 example: Build a CRUD Rest APIs</a>
Or APIs with GraphQL:<a href="https://www.bezkoder.com/spring-boot-graphql-example/">Spring Boot + GraphQL example</a>

More JPA queries at:
- <a href="https://www.bezkoder.com/spring-jpa-query/">Spring JPA @Query example</a>
- <a href="https://www.bezkoder.com/jpa-repository-query/">JPA Repository query example | Derived Query</a>
- <a href="https://www.bezkoder.com/jpa-native-query/">JPA Native Query example</a>

Validation:
<a href="https://www.bezkoder.com/spring-boot-validate-request-body/">Validate Request Body in Spring Boot</a>

Reactive with R2DBC:
<a href="https://www.bezkoder.com/spring-boot-r2dbc-h2/">Spring Boot R2DBC + H2 example</a>

Documentation: <a href="https://www.bezkoder.com/spring-boot-swagger-3/">Spring Boot + Swagger 3 example (with OpenAPI 3)</a>
Caching: <a href="https://www.bezkoder.com/spring-boot-redis-cache-example/">Spring Boot Redis Cache example</a>