Implement Delete Task

Now that we can create, retrieve, and update tasks, let's implement the ability to delete them. However, rather than just a simple delete like we used in TaskLists, let’s make use of transactions as it’s a great topic to move onto once you’ve completed this project.

Updating the Service Interface

First, let's add the delete method to our TaskService interface:

public interface TaskService { List<Task> listTasks(UUID taskListId); Task createTask(UUID taskListId, Task task); Optional<Task> getTask(UUID taskListId, UUID taskId); Task updateTask(UUID taskListId, UUID taskId, Task task); void deleteTask(UUID taskListId, UUID taskId); // Add this method }

Implementing the Service Method

Now let's implement the delete functionality in TaskServiceImpl:

@Service public class TaskServiceImpl implements TaskService { private final TaskListRepository taskListRepository; private final TaskRepository taskRepository; public TaskServiceImpl(TaskListRepository taskListRepository, TaskRepository taskRepository) { this.taskListRepository = taskListRepository; this.taskRepository = taskRepository; } @Transactional @Override public void deleteTask(UUID taskListId, UUID taskId) { taskRepository.deleteByTaskListIdAndId(taskListId, taskId); } }

Let's examine the key aspects of this implementation:

  1. @Transactional Annotation:

    • The @Transactional annotation ensures the delete operation happens within a database transaction
    • If any part of the delete operation fails, the entire operation is rolled back
    • This maintains database consistency even if errors occur during deletion
    • Particularly important when deleting related data or updating multiple records
  2. Method Parameters:

    • taskListId to scope the operation to a specific task list
    • taskId to identify the specific task to delete
  3. Repository Method:

    • Uses a specific deleteByTaskListIdAndId method to ensure task ownership
    • Spring Data JPA generates the appropriate DELETE query
    • The transaction ensures atomicity of the delete operation

Why @Transactional is Important

The @Transactional annotation is crucial for database operations like deletion because it:

  1. Ensures Atomicity:

    • The operation either completely succeeds or completely fails
    • No partial deletions that could leave the database in an inconsistent state
  2. Manages Database Connections:

    • Automatically handles database connection acquisition and release
    • Prevents connection leaks even if exceptions occur
  3. Provides Rollback Support:

    • Automatically rolls back changes if an exception occurs
    • Maintains data consistency in error scenarios
  4. Handles Related Data:

    • Ensures proper cleanup of related records
    • Maintains referential integrity

Updating the Controller

Now let's add the delete endpoint to our TasksController:

@RestController @RequestMapping(path = "/task-lists/{task_list_id}/tasks") public class TasksController { private final TaskService taskService; private final TaskMapper taskMapper; public TasksController(TaskService taskService, TaskMapper taskMapper) { this.taskService = taskService; this.taskMapper = taskMapper; } @DeleteMapping(path = "/{task_id}") public void deleteTask( @PathVariable("task_list_id") UUID taskListId, @PathVariable("task_id") UUID taskId) { taskService.deleteTask(taskListId, taskId); } }

Let's break down the key components:

  1. URL Mapping:

    • @DeleteMapping maps this to HTTP DELETE requests
    • Path includes both task list ID and task ID
    • Maintains REST resource hierarchy (/task-lists/{task_list_id}/tasks/{task_id})
  2. Parameters:

    • Two @PathVariable annotations extract IDs from the URL
    • No request body needed for delete operations
  3. Implementation:

    • Simply delegates to the service layer
    • Returns void, which Spring will convert to a 200 OK response
    • No response body needed for DELETE operations

How It Works Together

When a DELETE request arrives at /task-lists/{task_list_id}/tasks/{task_id}:

  1. Spring extracts both IDs from the URL path
  2. The controller calls taskService.deleteTask()
  3. A transaction begins
  4. The service delegates to taskRepository.deleteByTaskListIdAndId()
  5. The repository:
    • Deletes the task if it exists
    • Does nothing if the task doesn't exist
  6. The transaction commits
  7. Spring sends a 200 OK response with no body

For example, a DELETE request to /task-lists/123/tasks/789 will:

  • Begin a transaction
  • Delete the task with ID "789" if it exists within task list "123"
  • Commit the transaction
  • Return a 200 OK status with no body

Testing the Implementation

We can test our delete functionality through the frontend:

  1. Create a task list and add some tasks
  2. Select a task you want to delete
  3. Send a DELETE request to the appropriate endpoint
  4. Verify the task is removed by listing the tasks again

The frontend should see the task disappear from the list after a successful deletion.

Summary

  • Added delete functionality to the TaskService with proper transaction management
  • Used @Transactional to ensure atomic delete operations
  • Implemented a DELETE endpoint in the controller
  • Maintained proper task list scoping for the delete operation
© 2026 Devtiro Ltd. All rights reserved