To make your Spring Boot REST API return custom error messages when validation fails, you need to:
- Use Bean Validation annotations like
@NotNull,@Size, etc. - Handle validation errors using a custom
@ControllerAdviceclass that captures and formats those errors.
Step-by-Step Guide
Step 1: Add Validation Dependency
If you’re using Maven, make sure you have this in your pom.xml:
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
Or for older versions:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Step 2: Annotate Your Request DTO
Example DTO with validation annotations:
public class UserRequest {
@NotBlank(message = "Name must not be blank")
private String name;
@Email(message = "Invalid email format")
private String email;
@Min(value = 18, message = "Age must be at least 18")
private int age;
// Getters and Setters
}
Step 3: Use @Valid in Your Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest userRequest) {
// your logic here
return ResponseEntity.ok("User created");
}
}
Step 4: Create a Global Exception Handler
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidationErrors(MethodArgumentNotValidException ex) {
Map<String, Object> errors = new LinkedHashMap<>();
errors.put("timestamp", LocalDateTime.now());
errors.put("status", HttpStatus.BAD_REQUEST.value());
List<String> validationErrors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.toList());
errors.put("errors", validationErrors);
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
Sample JSON Response on Validation Error:
{
"timestamp": "2025-09-26T20:00:00",
"status": 400,
"errors": [
"email: Invalid email format",
"age: Age must be at least 18"
]
}
Optional: Customize Further
You can create a fully custom response object:
public class ErrorResponse {
private String message;
private List<String> details;
public ErrorResponse(String message, List<String> details) {
this.message = message;
this.details = details;
}
// Getters and setters
}
And return it like this:
ErrorResponse errorResponse = new ErrorResponse("Validation Failed", validationErrors);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
