Spring Boot: From Basics to Production · Validation and Error Handling
Bean Validation
Validate requests with Jakarta Bean Validation annotations.
Add the validation starter and annotate DTO fields with Jakarta Bean Validation constraints (@NotBlank, @Email, @Size, @Positive, @Past). @Valid on a @RequestBody triggers validation; failures throw MethodArgumentNotValidException, returned as 400. Use @Valid on nested objects and lists, and validation groups when create and update need different rules.
public record RegisterRequest(
@NotBlank @Email String email,
@NotBlank @Size(min = 12, max = 128) String password,
@NotNull @Past LocalDate birthDate,
@Valid @NotNull AddressRequest address,
@Size(max = 5) List<@NotBlank String> interests) {}
public record AddressRequest(@NotBlank String street, @NotBlank @Pattern(regexp = "[A-Z]{2}") String country) {}
@PostMapping("/api/v1/users")
ResponseEntity<UserResponse> register(@Valid @RequestBody RegisterRequest request) { /* ... */ }
Common pitfalls
- Forgetting
@Valid— annotations alone do nothing. - Missing
@Validon nested objects. - Duplicating business rules (like uniqueness) as annotations that need database access.
Key points
- Constraints on DTO fields
- @Valid triggers validation (also nested)
- Business rules in services
Further reading: Spring: Bean Validation
Practice questions
Why might @NotBlank on a nested DTO field not be enforced?
Answer
Nested objects are only validated if the field referencing them is annotated with @Valid.
Where should a 'username must be unique' rule live?
Answer
In the service layer (backed by a database unique constraint), since it requires I/O and must be enforced atomically.
Open in the app to mark lessons complete, take notes and track your progress.