Abhishek Singh
9 min readFeb 8, 2023

--

Creating CRUD Rest API with Spring Boot and JPA :

In this blog we are going to learn how to make CRUD operation using Spring Boot and JPA , JPA provides methods to perform operations like Create, Read, Update and Delete(CRUD)

In this blog you will learn :

  • What is a REST API?
  • Basics of designing REST API
  • How to configure Spring Data, JPA, Hibernate to work with Databases
  • How to use Spring Data JPA to interact with MySQL Database
  • How to define Data Models Layer, Service Layer and Repository interfaces i.e Data Layer
  • How to create Spring Rest Controller to process HTTP requests
  • How to execute different kinds of REST API with Postman?

So lets get started :

API Overview :

We will be building a Spring Boot JPA Rest CRUD API for a Employee application where :

  • Each employee will be having employee id, first name, last name, email and their salary
  • This will help us to create, retrieve, update and delete employees

These are APIs endpoints or http methods that we will create to manage employees :

  • Create a new employee : @PostMapping("/api/v1/emp")
  • Retrieve all employees : @GetMapping("/api/v1/emp")
  • Get details of a specific employee : @GetMapping("/api/v1/emp/{id}")
  • Update employee details : @PutMapping("/api/v1/emp/{id}")
  • Delete a employee: @DeleteMapping("/api/v1/emp/{id}")

So lets get started :

First we will dig into What is Api?

API is a set of services available for performing certain task, API enables two software components to communicate with each other using a set of definitions and protocols, APIs are intended to be used by programmers not by end user, API stands for Application Programming Interface in which Application refers to any software with distinct function and Interface is the contract of service between two application or two software components and for Web APIs we have SOAP APIs that uses Simple Object Access Protocol and client and server exchange messages using XML and it is a less flexible API that was more popular in the past, Now the REST APIs are the most popular and flexible API found on the web today and clients and servers exchange data via web services using HTTP with Json as the primary data format and the types of APIs by scope of use and some other examples of apis are :

Java Stream API is the java programming language API that allows us to use collections of data structures easily and flexibly, Java Servlet API is the Software Libraries API that enables programmers to build web applications running on the Java platform, JDBC API is the remote API that enables Java applications to talk to remote database servers.

What is a REST API?

REST stands for Representational State Transfer and REST is not a protocol or standard It’s a set of architectural constraints, REST was created by computer scientist Roy Fielding in 2000 in his doctoral research and as compared to a SOAP that uses XML messaging, REST APIs are easier to
use, faster and more lightweight and have better scalability.

And note that the main feature of rest API is statelessness and that’s why it is called representational state transfer and a request is self descriptive and has enough context for the server to possess it and servers do not save any data related to client requests and no server side sessions are required and each request is separate and unconnected and statelessness makes the rest API have better scalability.

  • Basics of designing a REST API :

Rest and Http :

REST is built on top of HTTP (Hypertext Transfer Protocol)

HTTP is the language of the web, HTTP has a few important verbs

  • POST : Create a new resource
  • GET : Read a resource
  • PUT : Update an existing resource
  • DELETE : Delete a resource

HTTP defines standard response codes :

  • 200 : SUCCESS
  • 404 : RESOURCE NOT FOUND
  • 400 : BAD REQUEST
  • 201 : CREATED
  • 401 : UNAUTHORIZED
  • 500 : INTERNAL SERVER ERROR

How to configure Spring Data, JPA, Hibernate to work with Database :

Lets now get started by creating a project so to create project i will be using Spring Initializr — Spring Boot tool so now go to https://start.spring.io/ and create a simple project like this :

Project Created Using Spring initializr

Now click on GENERATE and it will create a spring boot maven project with all the selected dependencies, now in the next step import this maven project in your favorite IDE i will be using STS ide you can use any ide of your choice..

Now open the pom.xml file and you will be able to see all the info and dependencies which you provided during project creation and it will look like this :

pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.abhishek</groupId>
<artifactId>spring-boot-jpa-crud-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-jpa-crud-example</name>
<description>Spring Boot Jpa Crud Example</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
  • How to use Spring Data JPA to interact with MySQL Database

Now open application.properties file and provide the following details:

server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/emp_db
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql=true
  • How to define Data Models Layer, Service Layer and Repository interfaces i.e Data Layer

Now the next step is to create the models or entity so create a simple java Employee class like this and provide all the annotations like this which will be used by JPA to connect with database tables :

Employee.java

package com.abhishek.springboot.jpa.crud.example.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "employees")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
@Column(name = "salary")
private Double salary;

}

Now lets define the Employee Repository :

EmployeeRepository.java

package com.abhishek.springboot.jpa.crud.example.repo;

import org.springframework.data.jpa.repository.JpaRepository;

import com.abhishek.springboot.jpa.crud.example.entity.Employee;

public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}

Now lets define the Employee Service Layer with all the methods :

EmployeeService.java

package com.abhishek.springboot.jpa.crud.example.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.abhishek.springboot.jpa.crud.example.entity.Employee;
import com.abhishek.springboot.jpa.crud.example.exceptions.ResourceNotFoundException;
import com.abhishek.springboot.jpa.crud.example.repo.EmployeeRepository;

@Service
public class EmployeeService {

@Autowired
private EmployeeRepository employeeRepository;

public List<Employee> findAllEmployees() {
return employeeRepository.findAll();
}

public Optional<Employee> getEmployeeById(long employeeId) {
return employeeRepository.findById(employeeId);
}

public Employee createEmployee(Employee employee) {
return employeeRepository.save(employee);
}

public Employee updateEmployee(Long employeeId, Employee employeeDetails) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

employee.setEmail(employeeDetails.getEmail());
employee.setLastName(employeeDetails.getLastName());
employee.setFirstName(employeeDetails.getFirstName());
Employee updatedEmployee = employeeRepository.save(employee);
return updatedEmployee;
}

public Map<String, String> deleteEmployee(Long employeeId) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

employeeRepository.delete(employee);
Map<String, String> response = new HashMap<>();
response.put("message", "Given Employee with id : "+ employeeId + " is deleted");
return response;
}

}
  • How to create Spring Rest Controller to process HTTP requests :

EmployeeController.java

package com.abhishek.springboot.jpa.crud.example.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.abhishek.springboot.jpa.crud.example.entity.Employee;
import com.abhishek.springboot.jpa.crud.example.exceptions.ResourceNotFoundException;
import com.abhishek.springboot.jpa.crud.example.service.EmployeeService;

@RestController
@RequestMapping("/api/v1")
public class EmployeeController {

@Autowired
private EmployeeService employeeService;

@GetMapping("/emp")
public List<Employee> getAllEmployees() {
return employeeService.findAllEmployees();
}

@GetMapping("/emp/{id}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeService.getEmployeeById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee does not exists with this : " + employeeId));
return ResponseEntity.ok().body(employee);
}

@PostMapping("/emp")
public Employee saveEmployee(@Valid @RequestBody Employee employee) {
return employeeService.createEmployee(employee);
}

@PutMapping("/emp/{id}")
public ResponseEntity<Employee> updateEmployee(@PathVariable(value = "id") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {

Employee updatedEmployee = employeeService.updateEmployee(employeeId, employeeDetails);

return ResponseEntity.ok(updatedEmployee);

}

@DeleteMapping("/emp/{id}")
public Map<String, String> deleteEmployee(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {

employeeService.deleteEmployee(employeeId);

Map<String, String> response = new HashMap<>();
response.put("message", "Employee with id : "+ employeeId + " has been deleted");
return response;
}

}

How to handle Exception if any unwanted data is sent from client to the server so here comes the exception handling so we will create like this :

package com.abhishek.springboot.jpa.crud.example.exceptions;
public class CustomException extends RuntimeException {

private static final long serialVersionUID = 1L;

public CustomException(String message) {
super(message);

}
}
package com.abhishek.springboot.jpa.crud.example.exceptions;

import java.time.LocalDateTime;

import com.fasterxml.jackson.annotation.JsonFormat;

public class ExceptionResponse {
//The message that we want to display to the end user.
private String message;
private String details;
//Time when an exception is thrown
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh-mm-ss")
private LocalDateTime timestamp;

public String getMessage() {
return message;
}

public String getDetails() {
return details;
}

public LocalDateTime getTimestamp() {
return timestamp;
}

public void setMessage(String message) {
this.message = message;
}

public void setDetails(String details) {
this.details = details;
}

public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
}
package com.abhishek.springboot.jpa.crud.example.exceptions;

import java.time.LocalDateTime;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ExceptionResponse response = new ExceptionResponse();
response.setMessage(ex.getMessage());
response.setDetails("NOT_FOUND");
response.setTimestamp(LocalDateTime.now());
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<?> globleExcpetionHandler(Exception ex, WebRequest request) {
ExceptionResponse errorDetails = new ExceptionResponse();
ExceptionResponse response = new ExceptionResponse();
response.setMessage(ex.getMessage());
response.setDetails("INTERNAL_SERVER_ERROR");
response.setTimestamp(LocalDateTime.now());
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(ResourceAlreadyExists.class)
public ResponseEntity<ExceptionResponse> resourceAlreadyExists(ResourceAlreadyExists ex) {
ExceptionResponse response = new ExceptionResponse();
response.setMessage(ex.getMessage());
response.setDetails("CONFLICT");
response.setTimestamp(LocalDateTime.now());
return new ResponseEntity<ExceptionResponse>(response, HttpStatus.CONFLICT);
}

@ExceptionHandler(CustomException.class)
public ResponseEntity<ExceptionResponse> customException(CustomException ex) {
ExceptionResponse response = new ExceptionResponse();
response.setMessage(ex.getMessage());
response.setDetails("BAD_REQUEST");
response.setTimestamp(LocalDateTime.now());
return new ResponseEntity<ExceptionResponse>(response, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(UnauthorizedException.class)
public ResponseEntity<ExceptionResponse> unauthorizedException(UnauthorizedException ex) {
ExceptionResponse response = new ExceptionResponse();
response.setMessage(ex.getMessage());
response.setDetails("UNAUTHORIZED");
response.setTimestamp(LocalDateTime.now());

return new ResponseEntity<ExceptionResponse>(response, HttpStatus.UNAUTHORIZED);
}
}
package com.abhishek.springboot.jpa.crud.example.exceptions;

public class ResourceAlreadyExists extends RuntimeException {

private static final long serialVersionUID = 1L;

public ResourceAlreadyExists(String message) {
super(message);
}
}
package com.abhishek.springboot.jpa.crud.example.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends Exception {

private static final long serialVersionUID = 1L;

public ResourceNotFoundException(String message){
super(message);
}
}
package com.abhishek.springboot.jpa.crud.example.exceptions;

public class UnauthorizedException extends RuntimeException {

private static final long serialVersionUID = 1L;

public UnauthorizedException(String message) {
super(message);
}
}
  • How to execute different kinds of REST API with Postman?
  • Create a new employee : @PostMapping("/api/v1/emp")
  • Retrieve all employees : @GetMapping("/api/v1/emp")
  • Get details of a specific employee : @GetMapping("/api/v1/emp/{id}")
  • Update employee details : @PutMapping("/api/v1/emp/{id}")
  • Delete a employee: @DeleteMapping("/api/v1/emp/{id}")

Now is the time to test the api which we have created.

Open the postman client :

first we will create a employee :

Create a new employee : @PostMapping("/api/v1/emp")

choose POST from the menu and provide this url http://localhost:8080/api/v1/emp and in body section select raw and provide employee details in json format

Now you see the status code is 200 OK it means this employee data is persisted in database..

Now we will retrieve all the employees from the database :

  • Retrieve all employees : @GetMapping("/api/v1/emp")

Now we will get details of specific employee :

  • Get details of a specific employee : @GetMapping("/api/emp/{id}")

Now we will update a employee details : here i am updating lastname and salary of the employee

  • Update employee details : @PutMapping("/api/v1/emp/{id}")

Now in the final step we will be performing delete operation on the resource so we will be deleting a employee :

Delete a employee: @DeleteMapping("/api/v1/emp/{id}")

And wow you got the message like Employee with id : 1 has been deleted

that’s cool right so how simple it is to create CRUD operation on a resource and we can expose all the endpoints using spring data rest and jpa..

Thats all in this blog see you in the next blog till then Happy Learning!

You can check my git repo here : https://github.com/abhishek621

--

--