Build a RESTful CRUD Service With Spring Boot, Hibernate, and JPA
A complete guide to writing a RESTful CRUD service using Spring Boot, Hibernate, and JPA, as well as testing the using GET, DELETE, PUT, and POST calls.
Join the DZone community and get the full member experience.
Join For FreeA CRUD REST service allows HTTP GET, POST, PUT, and DELETE endpoints on the underlying resource. A client can use these endpoints to Create, Read, Update, and Delete resources by providing respective resource identifiers.
This tutorial gives a step-by-step way of building your own RESTful CRUD service in Spring Boot to perform CRUD operations on a database resource by using Spring Data JPA and Hibernate.
We will write a Students Service, which is an example of Spring Boot REST application. The service allows clients to add new students, find students, and modify or delete any existing students. On the backend we will use an H2 database to store students' information.
In this tutorial, we will cover:
- The required POM Dependencies.
- How to create an Entity Class for Students.
- How to write a Spring Data Repository.
- How to write a REST Controller that has CRUD APIs.
- How to test our app.
Maven Dependencies
In order to run a basic Spring Boot JPA project we need web starter and data-jpa starter dependencies.
<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-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
We have also added an H2 database dependency, which is a Java-based, in-memory database. Spring Boot, by default, connects to an H2 database, if the database is available on the class path. In other words, we do not need to provide any connection details for this database.
Write an Entity Bean
We will create a Student
class that has an @Entity
annotation, to make it an entity bean. Also, the student class has basic fields, where the Id
is an autogenerated incremental field.
package com.amitph.spring.tutorials.students.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class Student {
strategy = GenerationType.IDENTITY) (
private Long student_id;
private String firstName;
private String lastName;
private int year;
}
We are using Lombok @Data
annotations, which auto-generates all the getters and setters for this class.
Create JPA Repository
Next, we will write a repository interface which extends from JpaRepository
. Interestingly, we have not added any methods to this interface nor are we going to provide any implementation class for this. This is because Spring Boot Data JPA autoimplements this interface.
xxxxxxxxxx
package com.amitph.spring.tutorials.students.entity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
public interface StudentRepository extends JpaRepository<Student, Long> {
}
Write a Rest Controller
Next, we will write a Rest Controller for students and provide all the CRUD methods.
xxxxxxxxxx
package com.amitph.spring.tutorials.students;
import com.amitph.spring.tutorials.students.entity.StudentRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
public class StudentsController {
private final StudentRepository studentRepository;
}
Write a POST Method
A POST method is used to create a new resource. Thus, we are using it to create new students, one at time.
x
"/students") (
public void postStudent( StudentDto studentDto) {
Student student = new Student();
student.setFirstName(studentDto.getFirstName());
student.setLastName(studentDto.getLastName());
student.setYear(studentDto.getYear());
studentRepository.save(student);
}
Users will send a POST request with the student details. The Spring Boot @RequestBody
annotation maps the request body parameters into the StudentDto
object. Next, we create a new instance of an entity bean and set all the fields. However, we do not set the id
field, because it is auto-generated by Hibernate. Finally, we ask the repository to save the newly created entity bean.
Write a PUT Method
The user sends a PUT request to modify an existing resource. Hence, our API endpoint needs a student Id in the request path.
x
"/students/{id}") (
public void putStudent( long id, StudentDto studentDto) {
Student student = new Student();
student.setStudent_id(id);
student.setFirstName(studentDto.getFirstName());
student.setLastName(studentDto.getLastName());
student.setYear(studentDto.getYear());
studentRepository.save(student);
}
We are mapping the request body into a StudentDto
object. Using that, we are creating a new Student
entity with the provided Id. Because we're using the same Id, Hibernate will not create a new record into the table. Instead, it will update the existing one.
Write a DELETE Method
Writing a DELETE is very straightforward. We expect a student Id to be present in the path variable. Thus, we can ask the repository to delete the particular resource using its Id.
x
"/students/{id}") (
public void deleteStudent( long id) {
studentRepository.deleteById(id);
}
Write a GET Method
Next is an example of a GET method where a user can pass a student Id as a path variable to get the Student. The endpoint throws StudentNotFoundException
if a student with particular Id is not found.
x
"/students/{id}") (
public Student getStudent( long id) {
return studentRepository
.findById(id)
.orElseThrow(StudentNotFoundException::new);
}
A user may want to get a complete list of students instead. To do that, we will create another GET endpoint, which is generic and returns a List of Student object.
x
"/students") (
public List<Student> getStudents() {
return studentRepository.findAll();
}
Handling a Not Found Exception
In the above endpoints, we throw a StudentNotFoundException
. This class is an extension of RuntimeException
, which returns HttpStatus.NOT_FOUND
(404) in response.
x
package com.amitph.spring.tutorials.students;
import org.springframework.web.bind.annotation.ResponseStatus;
import static org.springframework.http.HttpStatus.NOT_FOUND;
NOT_FOUND) (
public class StudentNotFoundException extends RuntimeException {
public StudentNotFoundException() {
super();
}
}
If you are unfamiliar with ResponseStatus
, please read Spring Rest Service Exception Handling.
Run and Test
Let’s run the application and test all the endpoints. To do that, we are using curl
, however, you can also use Postman or any similar tool.
Create a New Student
xxxxxxxxxx
~ curl --location --request POST 'localhost:8080/students' \
--header 'Content-Type: application/json' \
--data-raw '{
"firstName" : "Strong",
"lastName" : "Belwas",
"year" :2025
}'
Modify the Student
In the next example, we are changing the first name of the student, whose Id is 2.
xxxxxxxxxx
~ curl --location --request PUT 'localhost:8080/students/2' \
--header 'Content-Type: application/json' \
--data-raw '{
"firstName" : "JORY",
"lastName" : "CASSEL",
"year" : 2020
}'
Retrieve Students
We will call a GET on students by passing the Id 2. The output on the very next line shows the respective Student is correctly returned.
xxxxxxxxxx
~ curl --location --request GET 'localhost:8080/students/2'
{"student_id":2,"firstName":"JORY","lastName":"CASSEL","year":2020}%
We can also GET all students by omitting the path variable of Id.
xxxxxxxxxx
~ curl --location --request GET 'localhost:8080/students/'
[{"student_id":1,"firstName":"Strong","lastName":"Belwas","year":2025},{"student_id":2,"firstName":"JORY","lastName":"CASSEL","year":2020},{"student_id":3,"firstName":"Arthur","lastName":"Dayne","year":2022}]
Delete a Student
To delete a student, we will execute a DELETE request passing the Id as a path variable.
xxxxxxxxxx
~ curl --location --request DELETE 'localhost:8080/students/2'
Summary
In this hand-on tutorial, we learned how to write a Spring Boot CRUD REST API service using Hibernate and JPA. To do so, we wrote the most essential components along with individual HTTP request handlers. Finally, we tested our API by executing POST, PUT, GET, and DELETE endpoints.
Published at DZone with permission of Amit Phaltankar. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments