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:
- How to configure Spring Data REST, JPA, Hibernate to work with Database
- How to define Data Models and Repository interfaces
- Way to use Spring Data JPA to interact with H2 Database
- How to check CRUD operations with Postman
Spring Data REST
- Purpose: 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.
-
Features:
- Automatic generation of RESTful APIs for Spring Data repositories.
- Supports CRUD operations over HTTP (GET, POST, PUT, DELETE) for entities.
- Follows HATEOAS (Hypermedia as the Engine of Application State) principles, providing discoverable APIs.
- Customization of endpoints and response formats.
Usage: 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.
Spring Data REST example
We will build a Spring Boot Data REST example for a Tutorial application in that:
- Each Tutorial has id, title, description, published status.
- We can create, retrieve, update, delete Tutorials.
- We have custom finder methods such as find by published status or by title.
These are REST APIs that we provide:
Methods | Urls | Actions |
---|---|---|
POST | /api/tutorials | create new Tutorial |
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id
|
PUT | /api/tutorials/:id | update a Tutorial by :id
|
DELETE | /api/tutorials/:id | delete a Tutorial by :id
|
We also have APIs for:
filtering all published/unpublished Tutorials:
GET /api/tutorials/search/findByPublished?published=[status]
filtering all Tutorials which title contains
keyword
/api/tutorials/search/findByTitleContainingIgnoreCase?title=[keyword]
Technology
- Java 17 / 11 / 8
- Spring Boot 3 / 2 (with Spring Data REST, Spring Data JPA)
- H2 Database
- Maven
Project Structure
Let me explain it briefly.
– Tutorial
data model class corresponds to entity and table tutorials.
– TutorialRepository
is an interface that extends JpaRepository for CRUD methods and custom finder methods.
– Configuration for Spring Data REST, Datasource, JPA & Hibernate in application.properties.
– pom.xml 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:
Spring Boot One To Many example with JPA, Hibernate
Or add Tags with Many-to-Many Relationship:
Spring Boot Many to Many example with JPA, Hibernate
Create & Setup Spring Boot project
Use Spring web tool or your development tool (Spring Tool Suite, Eclipse, Intellij) to create a Spring Boot project.
Then open pom.xml and add these dependencies:
<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>
Configure Spring Data REST, JPA, h2, Hibernate
Under src/main/resources folder, open application.properties and write these lines.
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
-
spring.data.rest.basePath
: the root URI for Spring Data REST -
spring.datasource.url
:jdbc:h2:mem:[database-name]
for In-memory database andjdbc:h2:file:[path/database-name]
for disk-based database. -
spring.datasource.username
&spring.datasource.password
properties are the same as your database installation. - Spring Boot uses Hibernate for JPA implementation, we configure
H2Dialect
for H2 Database -
spring.jpa.hibernate.ddl-auto
is used for database initialization. We set the value toupdate
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 bevalidate
. -
spring.h2.console.enabled=true
tells the Spring to start H2 Database administration tool and you can access this tool on the browser:http://localhost:8080/h2-console
. -
spring.h2.console.path=/h2-ui
is for H2 console's url, so the default urlhttp://localhost:8080/h2-console
will change tohttp://localhost:8080/h2-ui
.
You can also alter the following Spring Data REST properties (starting with spring.data.rest.
):
-
defaultPageSize
: change the default for the number of items served in a single page. -
maxPageSize
: change the maximum number of items in a single page. -
pageParamName
: change the name of the query parameter for selecting pages. -
limitParamName
: change the name of the query parameter for the number of items to show in a page. -
sortParamName
: change the name of the query parameter for sorting. -
defaultMediaType
: change the default media type to use when none is specified. -
returnBodyOnCreate
: change whether a body should be returned when creating a new entity. -
returnBodyOnUpdate
: change whether a body should be returned when updating an entity.
Define Data Model
Our Data model is Tutorial with four fields: id, title, description, published.
In model package, we define Tutorial
class.
model/Tutorial.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...
}
-
@Entity
annotation indicates that the class is a persistent Java class. -
@Table
annotation provides the table that maps this entity. -
@Id
annotation is for the primary key. -
@GeneratedValue
annotation is used to define generation strategy for the primary key.GenerationType.AUTO
means Auto Increment field. -
@Column
annotation is used to define the column in database that maps annotated field.
Create Repository Interface
Let's create a repository to interact with Tutorials from the database.
In repository package, create TutorialRepository
interface that extends JpaRepository
.
repository/TutorialRepository.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 @RepositoryRestResource
. This annotation allows you to customize the RESTful endpoints and behavior, and path
defines the base URI path for the resource.
We also define custom finder methods:
-
findByPublished()
: returns all Tutorials withpublished
having value as inputpublished
. -
findByTitleContaining()
: returns all Tutorials which title contains inputtitle
.
The implementation is plugged in by Spring Data JPA automatically.
More Derived queries at:
JPA Repository query example in Spring Boot
Custom query with @Query
annotation:
Spring JPA @Query example: Custom query in Spring Boot
You can modify this Repository:
- to work with Pagination, the instruction can be found at: Spring Boot Pagination & Filter example | Spring JPA, Pageable
- or to sort/order by multiple fields with the tutorial: Spring Data JPA Sort/Order by multiple Columns | Spring Boot
You also find way to write Unit Test for this JPA Repository at:
Spring Boot Unit Test for JPA Repository with @DataJpaTest
Configure CORS in Spring Data REST
We add a @CrossOrigin
annotation to the repository interface to enable CORS for the whole TutorialRepository
repository.
By default, @CrossOrigin
allows all origins and HTTP methods.
repository/TutorialRepository.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.
@CrossOrigin(origins = "http://yourdomain.example",
methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE },
maxAge = 3600)
@RepositoryRestResource(path="tutorials")
public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
// ...
}
Run & Test
Run Spring Boot application with command: mvn spring-boot:run
.
tutorials table will be automatically generated in Database.
Let's open H2 console with url: http://localhost:8080/h2-ui
:
- For In-memory database:
- For on Disk database:
Click on Connect button, then check H2 database, you can see things like this:
Create some Tutorials:
Retrieve all Tutorials:
Retrieve a Tutorial by Id:
Update some Tutorials:
The table data is changed:
Spring Data REST to filter all published Tutorials:
Find all Tutorials which title contains string 'data':
Delete a Tutorial:
Check database and it has been already deleted.
Conclusion
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 JpaRepository
supports a great way to make CRUD operations and custom finder methods without need of boilerplate code.
Happy learning! See you again.
Further Reading
Fullstack CRUD App:
- Spring Boot Thymeleaf example
- Vue + Spring Boot example
- Angular 8 + Spring Boot example
- Angular 10 + Spring Boot example
- Angular 11 + Spring Boot example
- Angular 12 + Spring Boot example
- Angular 13 + Spring Boot example
- Angular 14 + Spring Boot example
- Angular 15 + Spring Boot example
- Angular 16 + Spring Boot example
- React + Spring Boot example
If you want to add Pagination to this Spring project, you can find the instruction at:
Spring Boot Pagination & Filter example | Spring JPA, Pageable
To sort/order by multiple fields:
Spring Data JPA Sort/Order by multiple Columns | Spring Boot
Or way to write Unit Test:
Spring Boot Unit Test for JPA Repository
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:
Spring Boot One To Many example with JPA, Hibernate
Or add Tags with Many-to-Many Relationship:
Spring Boot Many to Many example with JPA, Hibernate
Source Code
You can find the complete source code for this tutorial on Github.
With Rest Controller: Spring Boot JPA + H2 example: Build a CRUD Rest APIs
Or APIs with GraphQL:Spring Boot + GraphQL example
More JPA queries at:
Validation:
Validate Request Body in Spring Boot
Reactive with R2DBC:
Spring Boot R2DBC + H2 example
Documentation: Spring Boot + Swagger 3 example (with OpenAPI 3)
Caching: Spring Boot Redis Cache example