From 8b96433b1ae986be9b6910716c8e21f3a4f11601 Mon Sep 17 00:00:00 2001 From: Cedric Hornberger Date: Tue, 5 May 2026 17:28:47 +0200 Subject: [PATCH] feat: add CreateExpenseListRequest DTO with validation to POST /create endpoint Co-Authored-By: Claude Sonnet 4.6 --- .../controller/ExpenseListController.java | 4 +++- .../model/CreateExpenseListRequest.java | 17 +++++++++++++ .../controller/ExpenseListControllerTest.java | 24 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/zendric/app/xpensely_server/model/CreateExpenseListRequest.java diff --git a/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java b/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java index 52ea21d..3ef07f8 100644 --- a/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java +++ b/src/main/java/de/zendric/app/xpensely_server/controller/ExpenseListController.java @@ -58,9 +58,11 @@ public class ExpenseListController { } @PostMapping("/create") - public ResponseEntity create(@RequestBody ExpenseList expenseList, + public ResponseEntity create(@RequestBody @Valid CreateExpenseListRequest request, Authentication authentication) { AppUser authenticatedUser = authenticatedUserResolver.resolveCurrentUser(authentication); + ExpenseList expenseList = new ExpenseList(); + expenseList.setName(request.getName()); expenseList.setOwner(authenticatedUser); XpenselyStandardCategories standardCategories = categoryService.getDefaultCategories(); expenseList.setXpenselyStandardCategories(standardCategories); diff --git a/src/main/java/de/zendric/app/xpensely_server/model/CreateExpenseListRequest.java b/src/main/java/de/zendric/app/xpensely_server/model/CreateExpenseListRequest.java new file mode 100644 index 0000000..1bf3fa6 --- /dev/null +++ b/src/main/java/de/zendric/app/xpensely_server/model/CreateExpenseListRequest.java @@ -0,0 +1,17 @@ +package de.zendric.app.xpensely_server.model; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class CreateExpenseListRequest { + + @NotBlank(message = "List name is required") + @Size(max = 100, message = "List name must not exceed 100 characters") + private String name; +} diff --git a/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java b/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java index 4736738..65b043d 100644 --- a/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java +++ b/src/test/java/de/zendric/app/xpensely_Server/controller/ExpenseListControllerTest.java @@ -145,4 +145,28 @@ class ExpenseListControllerTest { .content("{\"name\":\"Groceries\"}")) .andExpect(status().isInternalServerError()); } + + @Test + void create_returns400_whenNameIsBlank() throws Exception { + AppUser user = new AppUser(); + user.setId(1L); + when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(user); + + mockMvc.perform(post("/api/expenselist/create") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"name\":\"\"}")) + .andExpect(status().isBadRequest()); + } + + @Test + void create_returns400_whenBodyIsEmpty() throws Exception { + AppUser user = new AppUser(); + user.setId(1L); + when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(user); + + mockMvc.perform(post("/api/expenselist/create") + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isBadRequest()); + } }