Implement Create Task
Now that we can list tasks, let's implement the ability to create new ones within a task list. We'll need to add methods to both our service and controller layers to handle this functionality.
Updating the Service Interface
First, let's add the create method to our TaskService interface:
public interface TaskService {
List<Task> listTasks(UUID taskListId);
Task createTask(UUID taskListId, Task task); // Add this method
}Implementing the Service Method
Now let's implement the create 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;
}
@Override
public Task createTask(UUID taskListId, Task task) {
if (null != task.getId()) {
throw new IllegalArgumentException("Task already has ID!");
}
if (null == task.getTitle() || task.getTitle().isBlank()) {
throw new IllegalArgumentException("Task must have a title");
}
TaskPriority priority = Optional.ofNullable(task.getPriority())
.orElse(TaskPriority.MEDIUM);
TaskList taskList = taskListRepository
.findById(taskListId)
.orElseThrow(() ->
new IllegalArgumentException("Invalid Task List ID provided")
);
LocalDateTime now = LocalDateTime.now();
return taskRepository.save(new Task(
null,
task.getTitle(),
task.getDescription(),
task.getDueDate(),
priority,
TaskStatus.OPEN,
now,
now,
taskList
));
}
}Let's examine the key aspects of this implementation:
-
Dependencies:
- We need both
TaskRepositoryandTaskListRepository TaskListRepositoryto verify the parent task list existsTaskRepositoryto save the new task
- We need both
-
Input Validation:
- Checks that the task doesn't already have an ID
- Ensures the title is not null or blank
- Verifies the parent task list exists
-
Default Values:
- Sets a default MEDIUM priority if none provided
- Sets status to OPEN for new tasks
- Sets created and updated timestamps to current time
-
Task List Association:
- Fetches the parent task list
- Associates the new task with its parent list
Updating the Controller
Now let's add the create 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;
}
@GetMapping
public List<TaskDto> listTasks(@PathVariable("task_list_id") UUID taskListId) {
return taskService.listTasks(taskListId)
.stream()
.map(taskMapper::toDto)
.toList();
}
@PostMapping
public TaskDto createTask(
@PathVariable("task_list_id") UUID taskListId,
@RequestBody TaskDto taskDto) {
Task createdTask = taskService.createTask(
taskListId,
taskMapper.fromDto(taskDto)
);
return taskMapper.toDto(createdTask);
}
}Let's break down the key components:
-
URL Mapping:
@PostMappingmaps this to HTTP POST requests- Path includes the parent task list ID
-
Parameters:
@PathVariableextracts the task list ID from the URL@RequestBodydeserializes the request body into a TaskDto
-
Implementation:
- Converts the incoming DTO to a Task entity
- Calls the service to create the task
- Converts the result back to a DTO for the response
How It Works Together
When a POST request arrives at /task-lists/{task_list_id}/tasks:
- Spring extracts the task list ID from the URL path
- The request body is deserialized into a TaskDto
- The controller converts the DTO to a Task entity
- The service:
- Validates the input
- Verifies the task list exists
- Sets default values and timestamps
- Saves the task
- The controller converts the saved entity back to a DTO
- Spring serializes the DTO to JSON for the response
For example, a POST request to /task-lists/123e4567-e89b-12d3-a456-426614174000/tasks might look like:
{
"title": "New Task",
"description": "This is a new task",
"dueDate": "2024-11-01T09:00:00",
"priority": "HIGH"
}And receive a response like:
{
"id": "789e4567-e89b-12d3-a456-426614174001",
"title": "New Task",
"description": "This is a new task",
"dueDate": "2024-11-01T09:00:00",
"priority": "HIGH",
"status": "OPEN"
}Summary
- Added create functionality to the
TaskService - Implemented input validation in the service layer
- Added the POST endpoint to create tasks