Building a Complete CRUD API with Spring Boot and H2 Database

Jaya Vel RajanJaya Vel Rajan
3 min read

Building a CRUD (Create, Read, Update, Delete) API is one of the foundational skills every backend developer should master. In this tutorial, we’ll walk through building a full-fledged CRUD REST API using Spring Boot and the in-memory H2 database.

This project is perfect for beginners who want to practice backend development without setting up an external database.


✅ What You’ll Build

We’ll create a simple Employee Management API with the following endpoints:

  • POST /employees – Create a new employee

  • GET /employees – Get all employees

  • GET /employees/{id} – Get a single employee by ID

  • PUT /employees/{id} – Update employee info

  • DELETE /employees/{id} – Delete employee


🛠️ Technologies Used

  • Java 17+

  • Spring Boot 3.x

  • Spring Web

  • Spring Data JPA

  • H2 Database


📦 Step 1: Set Up the Project

Visit https://start.spring.io and generate a new Maven project with:

  • Dependencies:

    • Spring Web

    • Spring Data JPA

    • H2 Database

Group: com.example
Artifact: crudapi

Extract and open the project in your IDE (e.g., IntelliJ or Eclipse).


📁 Step 2: Define the Entity

Create an Employee entity in com.example.crudapi.model:

package com.example.crudapi.model;

import jakarta.persistence.*;

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String role;

    // Constructors
    public Employee() {}

    public Employee(String name, String role) {
        this.name = name;
        this.role = role;
    }

    // Getters & Setters
    public Long getId() { return id; }
    public String getName() { return name; }
    public String getRole() { return role; }

    public void setId(Long id) { this.id = id; }
    public void setName(String name) { this.name = name; }
    public void setRole(String role) { this.role = role; }
}

🧩 Step 3: Create the Repository

Create a simple JPA repository in com.example.crudapi.repository:

package com.example.crudapi.repository;

import com.example.crudapi.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository<Employee, Long> {}
package com.example.crudapi.service;

import com.example.crudapi.model.Employee;
import com.example.crudapi.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    public List<Employee> getAll() {
        return repository.findAll();
    }

    public Optional<Employee> getById(Long id) {
        return repository.findById(id);
    }

    public Employee create(Employee employee) {
        return repository.save(employee);
    }

    public Employee update(Long id, Employee updated) {
        return repository.findById(id)
            .map(e -> {
                e.setName(updated.getName());
                e.setRole(updated.getRole());
                return repository.save(e);
            })
            .orElseThrow(() -> new RuntimeException("Employee not found"));
    }

    public void delete(Long id) {
        repository.deleteById(id);
    }
}

🌐 Step 5: Create the Controller

package com.example.crudapi.controller;

import com.example.crudapi.model.Employee;
import com.example.crudapi.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

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

    @Autowired
    private EmployeeService service;

    @GetMapping
    public List<Employee> getAll() {
        return service.getAll();
    }

    @GetMapping("/{id}")
    public Employee getById(@PathVariable Long id) {
        return service.getById(id)
            .orElseThrow(() -> new RuntimeException("Employee not found"));
    }

    @PostMapping
    public Employee create(@RequestBody Employee employee) {
        return service.create(employee);
    }

    @PutMapping("/{id}")
    public Employee update(@PathVariable Long id, @RequestBody Employee employee) {
        return service.update(id, employee);
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id) {
        service.delete(id);
    }
}

⚙️ Step 6: Configure H2 Database

In src/main/resources/application.properties:

# H2 DB Settings
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

Access H2 Console at:
➡️ http://localhost:8080/h2-console
Use
jdbc:h2:mem:testdb as JDBC URL.


🚀 Step 7: Run and Test

Run the CrudapiApplication.java main class.

Use Postman or cURL to test the API:

  • Create:
    POST /employees with body:

      { "name": "Alice", "role": "Engineer" }
    
  • Read all:
    GET /employees

  • Read by ID:
    GET /employees/1

  • Update:
    PUT /employees/1 with body:

      { "name": "Alice Smith", "role": "Senior Engineer" }
    
  • Delete:
    DELETE /employees/1

✅ Summary

You’ve successfully created a complete CRUD REST API using:

  • Spring Boot for the framework

  • Spring Data JPA for persistence

  • H2 for a lightweight, in-memory database

This is a perfect foundation for building more complex APIs. You can now connect to MySQL/PostgreSQL, add validations, implement DTOs, or secure your API with Spring Security.

0
Subscribe to my newsletter

Read articles from Jaya Vel Rajan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jaya Vel Rajan
Jaya Vel Rajan

Welcome to the captivating world of data! Meet Jaya Vel Rajan(that's me!), an aspiring data analyst and passionate data science enthusiast. My insatiable curiosity fuels their exploration of the power of data. Through my captivating blog, I share my knowledge in a unique and accessible way, making complex concepts a breeze. Join me on this thrilling journey, uncovering insights and shaping the future of data. Follow my blog for inspiring, informative, and dazzling content that will leave you amazed by the boundless possibilities of data! 🌟📊✨