Skip to content

feat(api): improve 422 handling — structured error body and unified validation flow #324

@coderabbitai

Description

@coderabbitai

Overview

Two follow-up improvements deferred from #319 (PR #323) to keep that change focused. Both relate to making 422 Unprocessable Entity handling more robust and consistent.


1. GlobalExceptionHandler — Return structured validation errors

Current behaviour: handleValidationException returns an empty 422 body (ResponseEntity<Void>).

Proposed improvement:

  • Build a response body from exception.getBindingResult() — either a ProblemDetail (RFC 9457, available since Spring 6 / Spring Boot 3) or a Map<String, String> of field → message.
  • Add SLF4J logging of the violations for observability.

Example sketch:

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ProblemDetail> handleValidationException(MethodArgumentNotValidException exception) {
    log.warn("Validation failed: {}", exception.getBindingResult().getAllErrors());
    ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.UNPROCESSABLE_ENTITY);
    problem.setDetail("Validation failed");
    Map<String, String> errors = exception.getBindingResult().getFieldErrors().stream()
        .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
    problem.setProperty("errors", errors);
    return ResponseEntity.unprocessableEntity().body(problem);
}

2. PlayersController.put — Delegate squad number mismatch to validation

Current behaviour: The inline mismatch check returns 422 directly inside the controller method, bypassing GlobalExceptionHandler.

Proposed improvement:

  • Introduce a cross-field constraint on PlayerDTO (e.g., a custom @SquadNumberMatch annotation), or
  • Throw a custom exception (e.g., SquadNumberMismatchException) and map it in GlobalExceptionHandler,

so that all 422 responses flow through a single, consistent handler.


References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions