Spring Boot CRUD Example with MongoDB: CRUD REST API Step-By-Step Guide

In this tutorial, we will build a Spring Boot CRUD (Create, Read, Update, Delete) application using MongoDB.

We will manage a Todo entity with fields: id, title, description, status, and createDate. We will use Java record for the DTO and follow best practices by keeping the conversion logic in the service layer.

We will develop CRUD RESTful web services for creating, reading, updating, and deleting todos.

Spring Boot Three-Layer Architecture

+-----------+      +-----------------+
|           |      | Controller Layer|
|  Postman  +----->+ (Handles HTTP   |
| (Client)  |      |  requests and   |
+-----------+      |  responses)     |
                   +--------+--------+
                            |
                            v
                   +--------+--------+
                   | Service Layer   |
                   | (Implements     |
                   |  business logic |
                   |  and data       |
                   |  transformations)|
                   +--------+--------+
                            |
                            v
                   +--------+--------+
                   | Repository Layer|
                   | (Manages data   |
                   |  operations with|
                   |  MongoDB)       |
                   +--------+--------+
                            |
                            v
                   +--------+--------+
                   |   MongoDB       |
                   | (Database for   |
                   |  storing data)  |
                   +-----------------+

Description of the diagram

  • Postman (Client): Acts as the client sending HTTP requests to the Spring Boot application. It’s typically used for testing and interacting with the API endpoints.
  • Controller Layer: This layer acts as the gateway to the application, receiving HTTP requests and directing them to the appropriate services. It also handles sending back the responses to the client.
  • Service Layer: Contains the core business logic for the application and handles data transformations. This layer processes data, applies business rules, and interacts with the Repository layer to execute data operations.
  • Repository Layer: Dedicated to managing data interactions with MongoDB. This layer performs CRUD operations directly on the MongoDB database, handling data retrieval, updates, deletions, and creations.
  • MongoDB: Serves as the backend database system for storing all application data. MongoDB is a NoSQL database that provides high performance, high availability, and easy scalability.

What You’ll Learn:

  • Setting up a Spring Boot project with MongoDB.
  • Configuring Spring Boot to connect to MongoDB.
  • Implementing CRUD operations using Spring Data MongoDB.
  • Using Java record for DTOs to transfer data.
  • Testing REST APIs using Postman.

Prerequisites

Before starting, make sure you have:

  • Java Development Kit (JDK) 17 or later
  • Apache Maven (for project management)
  • MongoDB (installed locally or accessible via MongoDB Atlas)
  • IDE (e.g., IntelliJ IDEA, Eclipse, or VS Code)
  • Postman (to test APIs)

Step 1: Setting Up the Project

1.1 Create a Spring Boot Project

  1. Open Spring Initializr.
  2. Configure the project metadata:
    • Project: Maven
    • Language: Java
    • Spring Boot Version: Latest (3.x)
    • Group: com.example
    • Artifact: spring-boot-mongodb-crud
    • Java Version: 17 or later
  3. Add the following dependencies:
    • Spring Web: For building RESTful web services.
    • Spring Data MongoDB: To interact with MongoDB using Spring Data.
    • Spring Boot DevTools: For hot reloading during development.
  4. Click Generate to download the project, extract the zip file, and open it in your IDE.

Explanation:

Spring Initializr helps generate a pre-configured Spring Boot project with all necessary dependencies to work with MongoDB. The Spring Data MongoDB dependency simplifies database interaction.

Step 2: Configuring MongoDB

2.1 Set Up MongoDB Database

If you have MongoDB installed locally, MongoDB will automatically create a new database and collections when you first insert data. If you’re using MongoDB Atlas (cloud), create a new cluster and connect your application to it.

2.2 Configure application.properties

In the src/main/resources/application.properties file, configure Spring Boot to connect to MongoDB:

# MongoDB configuration
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=TodoDB

For MongoDB Atlas, use:

spring.data.mongodb.uri=mongodb+srv://<username>:<password>@cluster0.mongodb.net/TodoDB

Replace <username> and <password> with your MongoDB Atlas credentials.

Explanation:

  • spring.data.mongodb.uri: If using MongoDB Atlas, this property will specify the connection URI.
  • spring.data.mongodb.host/port: Specifies the host and port for connecting to the local MongoDB instance.
  • spring.data.mongodb.database: Specifies the MongoDB database name, which will be created automatically when the first document is inserted.

Step 3: Creating the Todo Entity

3.1 Create the Todo Entity

In the model package, create a Java class named Todo to represent the document structure in MongoDB:

package com.example.springbootmongodbcrud.model;

import jakarta.persistence.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.time.LocalDate;

@Document(collection = "todos")
public class Todo {

    @Id
    private String id;
    private String title;
    private String description;
    private String status;
    private LocalDate createDate;

    // Getters and Setters
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }

    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }

    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }

    public LocalDate getCreateDate() { return createDate; }
    public void setCreateDate(LocalDate createDate) { this.createDate = createDate; }
}

Explanation:

  • @Document: Marks this class as a MongoDB document (equivalent to a table in relational databases).
  • @Id: Marks id as the unique identifier for each document.
  • The Todo entity has fields like title, description, status, and createDate.

Step 4: Creating the Repository

4.1 Create TodoRepository

In the repository package, create an interface TodoRepository that extends MongoRepository:

package com.example.springbootmongodbcrud.repository;

import com.example.springbootmongodbcrud.model.Todo;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TodoRepository extends MongoRepository<Todo, String> {
}

Explanation:

  • MongoRepository: Provides CRUD methods for interacting with MongoDB without writing custom queries.
  • @Repository: Marks this interface as a Spring Data repository.

Step 5: Using Java record for DTO

5.1 Create the TodoDTO Class

In the model package, create a Java record called TodoDTO:

package com.example.springbootmongodbcrud.model;

import java.time.LocalDate;

public record TodoDTO(String id, String title, String description, String status, LocalDate createDate) {}

Explanation:

  • Java record: A concise syntax for creating immutable data objects, automatically generating constructors, getters, toString(), equals(), and hashCode() methods, making it ideal for DTOs.

Step 6: Creating the Service Layer

6.1 Create TodoService Interface

In the service package, define an interface TodoService:

package com.example.springbootmongodbcrud.service;

import com.example.springbootmongodbcrud.model.TodoDTO;

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

public interface TodoService {
    List<TodoDTO> getAllTodos();
    Optional<TodoDTO> getTodoById(String id);
    TodoDTO saveTodo(TodoDTO todoDTO);
    TodoDTO updateTodo(String id, TodoDTO todoDTO);
    void deleteTodo(String id);
}

6.2 Implement TodoService in TodoServiceImpl

In the service implementation, add the conversion logic between Todo (entity) and TodoDTO (DTO):

package com.example.springbootmongodbcrud.service;

import com.example.springbootmongodbcrud.model.Todo;
import com.example.springbootmongodbcrud.model.TodoDTO;
import com.example.springbootmongodbcrud.repository.TodoRepository;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class TodoServiceImpl implements TodoService {

    private final TodoRepository todoRepository;

    public TodoServiceImpl(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    @Override
    public List<TodoDTO> getAllTodos() {
        return todoRepository.findAll().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public Optional<TodoDTO> getTodoById(String id) {
        return todoRepository.findById(id).map(this::convertToDTO);
    }

    @Override
    public TodoDTO saveTodo(TodoDTO todoDTO) {
        Todo todo = convertToEntity(todoDTO);
        Todo savedTodo = todoRepository.save(todo);
        return convertToDTO(savedTodo);
    }

    @Override
    public TodoDTO updateTodo(String id, TodoDTO todoDTO) {
        Todo todo = todoRepository.findById(id).orElseThrow();
        todo.setTitle(todoDTO.title());
        todo.setDescription(todoDTO.description());
        todo.setStatus(todoDTO.status());
        todo.setCreateDate(todoDTO.createDate());
        Todo updatedTodo = todoRepository.save(todo);
        return convertToDTO(updatedTodo);
    }

    @Override
    public void deleteTodo(String id) {
        todoRepository.deleteById(id);
    }

    // Convert Todo Entity to TodoDTO
    private TodoDTO convertToDTO(Todo todo) {
        return new TodoDTO(todo.getId(), todo.getTitle(), todo.getDescription(), todo.getStatus(), todo.getCreateDate());
    }

    // Convert TodoDTO to Todo Entity
    private Todo convertToEntity(TodoDTO todoDTO) {
        Todo todo = new Todo();
        todo.setTitle(todoDTO.title());
        todo.setDescription(todoDTO.description());
        todo.setStatus(todoDTO.status());
        todo.setCreateDate(todoDTO.createDate());
        return todo;
   

 }
}

Explanation:

  • The service layer handles the conversion between Todo and TodoDTO.
  • convertToDTO: Converts a Todo entity to TodoDTO.
  • convertToEntity: Converts a TodoDTO to a Todo entity.

Step 7: Creating the REST Controller

In the controller package, create the TodoController to expose REST APIs:

package com.example.springbootmongodbcrud.controller;

import com.example.springbootmongodbcrud.model.TodoDTO;
import com.example.springbootmongodbcrud.service.TodoService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/todos")
public class TodoController {

    private final TodoService todoService;

    public TodoController(TodoService todoService) {
        this.todoService = todoService;
    }

    @GetMapping
    public List<TodoDTO> getAllTodos() {
        return todoService.getAllTodos();
    }

    @GetMapping("/{id}")
    public ResponseEntity<TodoDTO> getTodoById(@PathVariable String id) {
        Optional<TodoDTO> todo = todoService.getTodoById(id);
        return todo.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
    }

    @PostMapping
    public TodoDTO createTodo(@RequestBody TodoDTO todoDTO) {
        return todoService.saveTodo(todoDTO);
    }

    @PutMapping("/{id}")
    public ResponseEntity<TodoDTO> updateTodo(@PathVariable String id, @RequestBody TodoDTO todoDTO) {
        try {
            TodoDTO updatedTodo = todoService.updateTodo(id, todoDTO);
            return ResponseEntity.ok(updatedTodo);
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteTodo(@PathVariable String id) {
        todoService.deleteTodo(id);
        return ResponseEntity.noContent().build();
    }
}

Explanation:

  • The controller exposes REST API endpoints for CRUD operations on Todo entities.
  • The controller delegates business logic to the service layer, keeping the code clean and organized.

Step 8: Running and Testing the Application

8.1 Running the Application

To run the application, open SpringBootMongodbCrudApplication.java and click the Run button in your IDE, or run the following command in the terminal:

./mvnw spring-boot:run

8.2 Testing with Postman

You can test the REST APIs using Postman:

  • GET all todos:
    • URL: http://localhost:8080/api/todos
    • Response: A list of todo DTOs.
  • GET todo by ID:
    • URL: http://localhost:8080/api/todos/{id}
    • Response: The todo data for the given ID.
  • POST create a new todo:
    • URL: http://localhost:8080/api/todos
    • Body:
      {
        "title": "Learn MongoDB",
        "description": "Study MongoDB and integrate it with Spring Boot.",
        "status": "IN_PROGRESS",
        "createDate": "2024-09-22"
      }
      
  • PUT update an existing todo:
    • URL: http://localhost:8080/api/todos/{id}
    • Body:
      {
        "title": "Complete MongoDB Tutorial",
        "description": "Complete the CRUD project with Spring Boot and MongoDB.",
        "status": "COMPLETED",
        "createDate": "2024-09-22"
      }
      
  • DELETE a todo:
    • URL: http://localhost:8080/api/todos/{id}
    • Response: No content (HTTP 204).

Conclusion

In this tutorial, we built a Spring Boot CRUD REST API with MongoDB using the Todo entity. We followed best practices by using Java record as the DTO for data transfer and keeping the conversion logic between the entity and DTO in the service layer. We also demonstrated how to test the APIs using Postman.

This guide provides a clear and efficient way to build a CRUD application with Spring Boot and MongoDB, making it easy to maintain and extend.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top