java 45 lines · 9 steps

Bean Validation in a Spring REST controller

A Spring controller validates request bodies with annotations and turns validation failures into structured 400 responses.

Explained by highlit
1@RestController
2@RequestMapping("/api/users")
3public class UserController {
4 
5 private final UserService userService;
6 
7 public UserController(UserService userService) {
8 this.userService = userService;
9 }
10 
11 @PostMapping
12 public ResponseEntity<UserResponse> create(@Valid @RequestBody CreateUserRequest request) {
13 User user = userService.register(request);
14 return ResponseEntity.status(HttpStatus.CREATED).body(UserResponse.from(user));
15 }
16}
17 
18public record CreateUserRequest(
19 @NotBlank(message = "name is required")
20 String name,
21 
22 @Email(message = "must be a valid email address")
23 @NotBlank(message = "email is required")
24 String email,
25 
26 @Size(min = 8, message = "password must be at least 8 characters")
27 String password
28) {}
29 
30@RestControllerAdvice
31public class ValidationExceptionHandler {
32 
33 @ExceptionHandler(MethodArgumentNotValidException.class)
34 @ResponseStatus(HttpStatus.BAD_REQUEST)
35 public ValidationErrorResponse handleValidation(MethodArgumentNotValidException ex) {
36 List<FieldErrorDetail> errors = ex.getBindingResult().getFieldErrors().stream()
37 .map(err -> new FieldErrorDetail(err.getField(), err.getDefaultMessage()))
38 .toList();
39 return new ValidationErrorResponse("Validation failed", Instant.now(), errors);
40 }
41 
42 public record ValidationErrorResponse(String message, Instant timestamp, List<FieldErrorDetail> errors) {}
43 
44 public record FieldErrorDetail(String field, String message) {}
45}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Pairing @Valid with @RequestBody makes Spring enforce Bean Validation constraints before your handler runs.
  2. 2A @RestControllerAdvice centralizes error formatting so every controller returns consistent failure responses.
  3. 3Records make concise, immutable DTOs for both incoming requests and outgoing error payloads.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Bean Validation in a Spring REST controller — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code