feat: add domain exceptions and global error handler
This commit is contained in:
1 parent
49b1e28855
commit
fcbef8490f
9 files changed
+150
No files matched your search
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class AvailabilityViolationException extends RuntimeException {
|
||||
|
||||
public AvailabilityViolationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class ForbiddenOperationException extends RuntimeException {
|
||||
|
||||
public ForbiddenOperationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.slotline.common;
|
||||
|
||||
import com.slotline.recurrence.RecurrenceException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ProblemDetail;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<ProblemDetail> handleNotFound(NotFoundException exception, HttpServletRequest request) {
|
||||
return problem(HttpStatus.NOT_FOUND, exception.getMessage(), request);
|
||||
}
|
||||
|
||||
@ExceptionHandler(InvalidCredentialsException.class)
|
||||
public ResponseEntity<ProblemDetail> handleInvalidCredentials(InvalidCredentialsException exception,
|
||||
HttpServletRequest request) {
|
||||
return problem(HttpStatus.UNAUTHORIZED, exception.getMessage(), request);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ForbiddenOperationException.class)
|
||||
public ResponseEntity<ProblemDetail> handleForbidden(ForbiddenOperationException exception,
|
||||
HttpServletRequest request) {
|
||||
return problem(HttpStatus.FORBIDDEN, exception.getMessage(), request);
|
||||
}
|
||||
|
||||
@ExceptionHandler({InvalidReservationException.class, RecurrenceException.class})
|
||||
public ResponseEntity<ProblemDetail> handleInvalidReservation(RuntimeException exception,
|
||||
HttpServletRequest request) {
|
||||
return problem(HttpStatus.BAD_REQUEST, exception.getMessage(), request);
|
||||
}
|
||||
|
||||
@ExceptionHandler(AvailabilityViolationException.class)
|
||||
public ResponseEntity<ProblemDetail> handleAvailability(AvailabilityViolationException exception,
|
||||
HttpServletRequest request) {
|
||||
return problem(HttpStatus.UNPROCESSABLE_ENTITY, exception.getMessage(), request);
|
||||
}
|
||||
|
||||
@ExceptionHandler({SlotConflictException.class, UsernameTakenException.class, SlugTakenException.class})
|
||||
public ResponseEntity<ProblemDetail> handleConflict(RuntimeException exception, HttpServletRequest request) {
|
||||
return problem(HttpStatus.CONFLICT, exception.getMessage(), request);
|
||||
}
|
||||
|
||||
@ExceptionHandler({ConcurrencyFailureException.class, DataIntegrityViolationException.class})
|
||||
public ResponseEntity<ProblemDetail> handleConcurrentBooking(RuntimeException exception,
|
||||
HttpServletRequest request) {
|
||||
return problem(HttpStatus.CONFLICT, "The slot was booked by a concurrent request", request);
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||
public ResponseEntity<ProblemDetail> handleUnreadable(HttpMessageNotReadableException exception,
|
||||
HttpServletRequest request) {
|
||||
return problem(HttpStatus.BAD_REQUEST, "Malformed request body", request);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ProblemDetail> handleValidation(MethodArgumentNotValidException exception,
|
||||
HttpServletRequest request) {
|
||||
List<FieldViolation> violations = exception.getBindingResult().getFieldErrors().stream()
|
||||
.map(error -> new FieldViolation(error.getField(), error.getDefaultMessage()))
|
||||
.toList();
|
||||
ResponseEntity<ProblemDetail> response = problem(HttpStatus.BAD_REQUEST, "Request validation failed", request);
|
||||
response.getBody().setProperty("violations", violations);
|
||||
return response;
|
||||
}
|
||||
|
||||
private ResponseEntity<ProblemDetail> problem(HttpStatus status, String detail, HttpServletRequest request) {
|
||||
ProblemDetail body = ProblemDetail.forStatusAndDetail(status, detail);
|
||||
body.setTitle(status.getReasonPhrase());
|
||||
body.setProperty("path", request.getRequestURI());
|
||||
return ResponseEntity.status(status).body(body);
|
||||
}
|
||||
|
||||
private record FieldViolation(String field, String message) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class InvalidCredentialsException extends RuntimeException {
|
||||
|
||||
public InvalidCredentialsException() {
|
||||
super("Invalid username or password");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class InvalidReservationException extends RuntimeException {
|
||||
|
||||
public InvalidReservationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class NotFoundException extends RuntimeException {
|
||||
|
||||
public NotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class SlotConflictException extends RuntimeException {
|
||||
|
||||
public SlotConflictException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class SlugTakenException extends RuntimeException {
|
||||
|
||||
public SlugTakenException(String slug) {
|
||||
super("Organization slug '" + slug + "' is already taken");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.slotline.common;
|
||||
|
||||
public class UsernameTakenException extends RuntimeException {
|
||||
|
||||
public UsernameTakenException(String username) {
|
||||
super("Username '" + username + "' is already taken");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user