Spring Data REST example

Tien Nguyen - Nov 21 '23 - - Dev Community

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

spring-data-rest-example-project

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>


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode
  • spring.data.rest.basePath: the root URI for Spring Data REST
  • spring.datasource.url: jdbc:h2:mem:[database-name] for In-memory database and jdbc: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 to update 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 validate.
  • 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 url http://localhost:8080/h2-console will change to http://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...

}


Enter fullscreen mode Exit fullscreen mode
  • @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);
}


Enter fullscreen mode Exit fullscreen mode

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 with published having value as input published.
  • findByTitleContaining(): returns all Tutorials which title contains input title.

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:

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> {
  // ...
}


Enter fullscreen mode Exit fullscreen mode

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> {
  // ...
}


Enter fullscreen mode Exit fullscreen mode

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:

spring-data-rest-example-h2-console-in-memory

  • For on Disk database:

spring-data-rest-example-h2-console-on-disk

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

spring-data-rest-example-database-table

Create some Tutorials:

spring-data-rest-example-crud-create

Retrieve all Tutorials:

spring-data-rest-example-crud-retrieve

Retrieve a Tutorial by Id:

spring-data-rest-example-crud-retrieve-one

Update some Tutorials:

spring-data-rest-example-crud-update

The table data is changed:

spring-data-rest-example-crud-update-database

Spring Data REST to filter all published Tutorials:

spring-data-rest-filter-example

Find all Tutorials which title contains string 'data':

spring-data-rest-search-example

Delete a Tutorial:

spring-data-rest-example-crud-delete

Check database and it has been already deleted.

spring-data-rest-example-crud-delete-table

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:

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .