Validation in Spring Boot REST APIs — A Complete Guide

3 min read

Validation in Spring Boot REST APIs — A Complete Guide

Building RESTful APIs often involves handling client input. To ensure data integrity and prevent invalid values from polluting your system, Spring Boot provides powerful validation mechanisms using Jakarta Bean Validation (JSR 380/381) with annotations such as @NotNull, @Size, @Email, and more.

In this guide, we’ll create a User Management REST API with full validation support.

Add Dependencies

Spring Boot automatically integrates validation if you include:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Create a DTO with Validation Annotations

We’ll define a UserRequest DTO with field-level constraints.

import jakarta.validation.constraints.*;

public class UserRequest {

    @NotNull(message = "Username cannot be null")
    @Size(min = 3, max = 20, message = "Username must be between 3–20 characters")
    private String username;

    @NotBlank(message = "Password is required")
    @Size(min = 8, message = "Password must be at least 8 characters")
    private String password;

    @Email(message = "Email should be valid")
    @NotBlank(message = "Email cannot be blank")
    private String email;

    @Min(value = 18, message = "Age must be at least 18")
    @Max(value = 100, message = "Age must be less than or equal to 100")
    private int age;

    @Pattern(regexp = "^(USER|ADMIN)$", message = "Role must be USER or ADMIN")
    private String role;

    // getters and setters
}

Annotations Used Here:

  • @NotNull, @NotBlank → ensures required fields.
  • @Size, @Min, @Max → enforce numeric/string ranges.
  • @Email → validates email format.
  • @Pattern → restricts allowed values.

Create a REST Controller with Validation

Use @Valid (or @Validated) to trigger validation on incoming requests.

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.*;

@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {

    private final Map<String, UserRequest> userDb = new HashMap<>();

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest userRequest) {
        userDb.put(userRequest.getUsername(), userRequest);
        return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully!");
    }

    @GetMapping("/{username}")
    public ResponseEntity<UserRequest> getUser(@PathVariable String username) {
        UserRequest user = userDb.get(username);
        if (user == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
        return ResponseEntity.ok(user);
    }
}

Annotations Used Here:

  • @RestController, @RequestMapping → REST setup.
  • @PostMapping, @GetMapping → specific HTTP methods.
  • @Valid → validates UserRequest.
  • @RequestBody, @PathVariable → bind request body and URL parameters.
  • @ResponseEntity → control status codes.
  • @Validated → enables advanced validation (method-level, groups).

Custom Exception Handling with @ControllerAdvice

When validation fails, Spring throws a MethodArgumentNotValidException.
We can handle it globally with @ControllerAdvice.

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationErrors(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
                errors.put(error.getField(), error.getDefaultMessage()));
        return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleOtherErrors(Exception ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

Annotations Used Here:

  • @ControllerAdvice → global error handling.
  • @ExceptionHandler → catch specific exceptions like validation errors.

Example API Calls

Valid Request

POST /api/users
Content-Type: application/json

{
  "username": "viet123",
  "password": "mypassword123",
  "email": "viet@example.com",
  "age": 25,
  "role": "ADMIN"
}

Response: 201 Created — "User created successfully!"

Invalid Request

POST /api/users
Content-Type: application/json

{
  "username": "vi",
  "password": "123",
  "email": "not-an-email",
  "age": 10,
  "role": "GUEST"
}

Response:

{
  "username": "Username must be between 3–20 characters",
  "password": "Password must be at least 8 characters",
  "email": "Email should be valid",
  "age": "Age must be at least 18",
  "role": "Role must be USER or ADMIN"
}

Final Thoughts

In this article, we demonstrated:

  • DTO validation with annotations like @NotNull, @Size, @Email, @Pattern.
  • Controller-level validation with @Valid and @Validated.
  • Exception handling with @ControllerAdvice and @ExceptionHandler.
  • Clean error responses for clients.

By leveraging these annotations, you can enforce strict validation rules in your Spring Boot REST APIs, making them robust, secure, and user-friendly.

🤞 Never miss a story from us, get weekly updates to your inbox!

Leave a Reply

Your email address will not be published. Required fields are marked *