Skip to content

Commit a77f7a1

Browse files
committed
implement API error model and 404 contract test for missing transaction
1 parent df4cd57 commit a77f7a1

5 files changed

Lines changed: 77 additions & 0 deletions

File tree

support_portal_backend/src/main/java/com/support/controller/TransactionController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.support.controller;
22

3+
import com.support.exception.ResourceNotFoundException;
34
import com.support.model.Transaction;
45
import com.support.repository.TransactionRepository;
56
import org.springframework.web.bind.annotation.*;
@@ -26,4 +27,10 @@ public List<Transaction> getAllTransactions() {
2627
public List<Transaction> getTransactionsByStatus(@PathVariable String status) {
2728
return repository.findByStatus(status);
2829
}
30+
31+
@GetMapping("/transactions/{id}")
32+
public Transaction getTransactionById(@PathVariable Long id) {
33+
return repository.findById(id)
34+
.orElseThrow(() -> new ResourceNotFoundException("Transaction not found with ID: " + id));
35+
}
2936
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.support.exception;
2+
3+
import com.support.model.ApiError;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.web.bind.annotation.ControllerAdvice;
8+
import org.springframework.web.bind.annotation.ExceptionHandler;
9+
10+
import java.time.LocalDateTime;
11+
12+
@ControllerAdvice
13+
public class GlobalExceptionHandler {
14+
15+
@ExceptionHandler(ResourceNotFoundException.class)
16+
public ResponseEntity<ApiError> handleNotFound(ResourceNotFoundException ex, HttpServletRequest request) {
17+
ApiError error = new ApiError(
18+
LocalDateTime.now(),
19+
HttpStatus.NOT_FOUND.value(),
20+
"Resource Not Found",
21+
ex.getMessage(),
22+
request.getRequestURI()
23+
);
24+
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
25+
}
26+
27+
@ExceptionHandler(Exception.class)
28+
public ResponseEntity<ApiError> handleGlobal(Exception ex, HttpServletRequest request) {
29+
ApiError error = new ApiError(
30+
LocalDateTime.now(),
31+
HttpStatus.INTERNAL_SERVER_ERROR.value(),
32+
"Internal Server Error",
33+
"An unexpected error occurred", // Don't leak raw stack traces in Payments!
34+
request.getRequestURI()
35+
);
36+
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
37+
}
38+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.support.exception;
2+
3+
public class ResourceNotFoundException extends RuntimeException {
4+
public ResourceNotFoundException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.support.model;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import java.time.LocalDateTime;
6+
7+
@Data
8+
@AllArgsConstructor
9+
public class ApiError {
10+
private LocalDateTime timestamp;
11+
private int status;
12+
private String error;
13+
private String message;
14+
private String path;
15+
}

support_portal_backend/src/test/java/com/support/controller/TransactionControllerTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,14 @@ public void shouldReturnEmptyListWhenNoTransactionsFound() throws Exception {
6969
.andExpect(status().isOk())
7070
.andExpect(content().json("[]"));
7171
}
72+
73+
@Test
74+
public void shouldReturn404WhenTransactionNotFound() throws Exception {
75+
when(repository.findById(99L)).thenReturn(java.util.Optional.empty());
76+
77+
mockMvc.perform(get("/api/support/transactions/99"))
78+
.andExpect(status().isNotFound())
79+
.andExpect(jsonPath("$.error").value("Resource Not Found"))
80+
.andExpect(jsonPath("$.message").contains("ID: 99"));
81+
}
7282
}

0 commit comments

Comments
 (0)