Spring Boot CRUD example with REST API

Spring Boot makes it easy to create stand-alone, production-grade Spring based applications with minimal configuration. In this article, we will create a Spring Boot CRUD example with REST API. We will use a H2 database to store data.

We’ll be creating a simple Employee Management System where employees can be created, read, updated and deleted.

Setting Up Project

This section will walk through the steps necessary to setup a Spring Boot application for developing RESTful APIs.

Go to Spring Initializr and add the following starter dependencies to a project.

  • Web
  • JPA
  • H2
rest api project

Change the Name to “springboot-crud-example” and then click on “Generate” button. A .zip will download. Unzip it. Inside you’ll find a simple, Maven-based project including a pom.xml build file (NOTE: You can use Gradle. The examples in this tutorial will be Maven-based.)

Import the project to your favorite IDE.

Configure Data Source Properties

We configure Data Source properties in application. properties file. As we are using H2 database

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE;
spring.datasource.username=sa
spring.datasource.password=password
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true

spring.datasource.initialization-mode=always
spring.jpa.defer-datasource-initialization=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.sql.init.mode=always

spring.h2.console.path=/h2-console
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false


Inserting sample data into database

create a file with .sql extension in resources directory and put insert sql commands to initialize the database during startup.

ALTER SEQUENCE hibernate_sequence RESTART WITH 1;

DELETE FROM EMPLOYEE;
DELETE FROM DEPARTMENT;


INSERT INTO DEPARTMENT(id,dept_name) VALUES(100,'HR');
INSERT INTO DEPARTMENT(id,dept_name) VALUES(101,'PDE');
INSERT INTO DEPARTMENT(id,dept_name) VALUES(102,'Marketing');


INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(100,'Alex','Bonilla','M','1990-12-07','2011-04-01',100);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(200,'Duke','Stacey','M','1989-07-11','2012-08-21',100);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(300,'Hayley','Drake','M','1992-10-01','2007-07-06',101);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(400,'Nancie','Beasley','M','1978-02-21','2003-03-03',101);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(500,'Wyatt','Holder','M','1994-12-01','2016-02-15',101);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(600,'Tobey','Drake','M','1992-10-01','2014-06-11',102);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(700,'Marvin','Hope','F','1978-02-21','2003-09-10',102);
INSERT INTO EMPLOYEE(id,first_name,last_name,gender,birth_date,hire_date,department_id) VALUES(800,'Ibrar','Garcia','F','1994-12-01','2004-12-21',102);

Code Domain Model Class

I am defining following two entities.

  • Department
  • Employee

Department and Employee entities have 1:N relationship

Department entity class

@Entity
public class Department implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String dept_name;
    @OneToMany(
            mappedBy = "department",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    @JsonIgnore
    private List<Employee> employees;

    public Department() {
    }
}Code language: Java (java)

Employee entity class

@Entity
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String first_name;
    private String last_name;

    @Enumerated(EnumType.STRING)
    private Gender gender;

    private LocalDate birth_date;
    private LocalDate hire_date;

    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;


    public Employee() {

    }

....
}Code language: Java (java)

Coding Repository Interfaces

Let’s define repository classes corresponding to Employee and Department entities.

public interface DepartmentRepository extends JpaRepository<Department,Integer> {
}
Code language: Java (java)
public interface  EmployeeRepository extends JpaRepository<Employee,Integer> {

   
}Code language: Java (java)

Code Service Class

@Service
public class EmployeeService {

    @Autowired
    EmployeeRepository employeeRepository;

    @Autowired
    DepartmentRepository departmentRepository;

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

    public Employee getEmployeeById(Integer id) {
        return employeeRepository.findById(id).orElseThrow( () -> new ResponseStatusException(HttpStatus.NOT_FOUND,"Resource Not found") );
    }

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

    public Employee updateEmpDepartment(Integer emp_id , Integer dept_id) {
        Employee employee = employeeRepository.getById(emp_id);
        if(employee == null) {
            throw new RestClientException("Employee with id "+emp_id+" not found");
        }

        Department department = departmentRepository.getById(dept_id);
        if(department == null) {
            throw new RestClientException("Department with id "+dept_id+" not found");
        }

        employee.setDepartment(department);
        employeeRepository.save(employee);

        return employee;
    }

    public List<Employee> findEmployeesByGender(Gender gender) {
        return employeeRepository.findByGender(gender);
    }

    public  List<Employee> searchEmployeesByGender(Gender gender) {
        return employeeRepository.searchByGender(gender);
    }

    public Employee updateEmployee(Employee employee) {
        Employee emp = employeeRepository.getById(employee.getId());
        if(emp == null) {
            throw new RestClientException("Employee with id "+employee.getId()+" not found");
        }
        return employeeRepository.save(employee);
    }

    public void deleteEmployee(Integer id) {
         employeeRepository.deleteById(id);
    }
}

Code language: Java (java)

Code REST Controller Class

Let’s implement CRUD functionality.

In Spring’s approach to building RESTful web services, HTTP requests are handled by a controller.

First we will create a EmployeeController class which contains all handler methods.

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeService;
}Code language: Java (java)

@RestController – annotation identifies spring boot Rest controller. The Spring Boot controller class returns domain object rather than a view for each method.

You can also mark every controller with @controller annotation but to return the domain object you need to add @ResponseBody annotation to class.

@RequestMapping annotation tells path to invoke this controller. This annotation can be used at class level and method level.

Difference between @RestController and @Controller

The @Controller is a specialization of @Component annotation while @RestController is a specialization of @Controller annotation

One of the key differences is once you mark a class @RestController then every method is written a domain object instead of a view.

Another key difference is that you don’t need to use @ResponseBody with  @RestController  annotationon every handler method

@RestController is shot hand for including both @Controller  and @ResponseBody

Create Operation

As the first handler method we will implement “Create” functionality.

 HTTP POST method is used to create a new resource on the server

For creating Employee, we will send the employee data to server in request body.

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeService;

    @PostMapping
    public Employee createEmployee(@RequestBody Employee employee) {
        return employeeService.createEmployee(employee);
    }
}Code language: Java (java)

@PostMapping – annotation ensures that HTTP POST requests to /employee are mapped to createEmployee method.

You can also use @RequestMapping(method=POST) annotation. @PostMapping is short form form of it.

@RequestBody – Binds the request body of the POST method to Employee object of createEmployee method.

HTTP POST method, by default sends response code 200 (HttpStatus.OK) when object is successfully created.

Since POST method creates object on the server it is better to create status 201 (HttpStatus.CREATED) indicating that the request has succeeded and has led to the creation of a resource.

To return Http status code 201, you can add @ResponseStatus annotation to post method like below

    @ResponseStatus(HttpStatus.CREATED) // send HTTP status code 201 instead of 200 
    @PostMapping   
    public Employee createEmployee(@RequestBody Employee employee) {

        return employeeService.createEmployee(employee);
    }

Retrieve Operation

Next we look at the retrieve functionality.

 HTTP GET method is used to retrieve resource from server.

For retrieving Employee data ,we use HTTP GET method.

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeService;
     
    @GetMapping("/{id}")
    public Employee getEmployee(@PathVariable Integer id) {
        Employee emp = employeeService.getEmployeeById(id);
        return emp;
    }
    
    @GetMapping()
    public List<Employee> getEmployees() {
        return employeeService.getAllEmployees();
    }
}Code language: Java (java)

The @GetMapping annotation ensures that HTTP GET requests to /employee are mapped to the getEmployee()/getEmployees method.

value=”/{id}”

We have defined 2 get method.

getEmployee(@PathVariable Integer id) – method retrieves the individual employee information based on the id provided.

@PathVariable binds the value of the path string parameter id into the id parameter of the getEmployee() method

HTTP GET method with url http://localhost:8080/employee/100 – will fetch the employee information of Emp Id : 100.

in above URL 100 is path parameter, which can be passed dynamically.

If you want name path variable and method parameter differently, you need to specify the path variable name like below to bind them.

@GetMapping("/{empid}")
    public Employee getEmployee(@PathVariable("empid") Integer id) {
        Employee emp = employeeService.getEmployeeById(id);
        return emp;
    }Code language: Java (java)

HTTP GET method with url http://localhost:8080/employee – will retrieve the information of all employees.

Update Operation

Next we look at the update functionality.

 HTTP PUT method is used to update resource on server.

@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeService;
     
    @PutMapping()
    public Employee updateEmployee(@RequestBody Employee employee) {
        return employeeService.updateEmployee(employee);
    }
}Code language: Java (java)

In some cases HTTP PATCH method is used to update the resource.

The HTTP PATCH request method applies partial modifications to a resource.

PATCH request is considered a set of instructions on how to modify a resource

 @PatchMapping("/{empId}/dept/{deptId}")
    public Employee updateEmpDepartment(@PathVariable("empId") Integer emp_id , @PathVariable("deptId") Integer dept_id) {
       return employeeService.updateEmpDepartment(emp_id,dept_id);
    }Code language: Java (java)

You can also send data in request body

@PatchMapping("/{empId}")
    public Employee updateEmpDepartmentbYId(@PathVariable("empId") Integer emp_id , @RequestBody Department department) {
        return employeeService.updateEmpDepartment(emp_id,department.getId());
    }Code language: Java (java)

Note

Some API implementations use HTTP POST method to update resource on server.

Delete Operation

Next we look at the update functionality.

 HTTP DELETE method is used to delete resource on server.

@DeleteMapping(value="/{id}")
    public  void deletePost(@PathVariable("id") Integer id){
        employeeService.deleteEmployee(id);
    }Code language: Java (java)

Testing Rest API

Now let’s test the developed REST API.

We need a REST client to test the functionality. I am going to use Tabbed Postman Rest client. This Rest client is chrome browser extension.

REST API

First start the Spring Boot application.

  1. Testing Create Employee

Open the Tabbed postman Rest client in browser and select the required details as shown below and click on send button

rest api

If the request is successful, new Employee will be created and id will be assigned him.

2. Testing Retrieve Employee

If employee exists with given id in the url , we should receive response

3. Testing Update functionality

If employee record updated successfully, you should receive response like below

4. Testing Delete functionality

If employee delete successfully, then we will not receive any response, we will only receive http status code 200.

Source code for blogpost can be downloaded from GitHub

You might be interested in

Similar Posts