Spring Boot @Valid Annotation: Simplifying Input Validation in REST APIs

Introduction :

Data validation is one of the most important aspects of any application. Before processing user input, we must ensure that the data received is valid and follows the required rules.

Spring Boot provides a powerful validation mechanism through the Bean Validation API using annotations such as @Valid, @NotNull, @NotBlank, @Size, and many others.

If you have worked on Spring Boot applications, you have probably come across situations where users submit invalid data. For example, a user may leave the name field empty, enter an invalid email address, or provide an age that doesn't make sense.

In my early projects, I used to write multiple if-else conditions to validate request data. While it worked, the code quickly became repetitive and difficult to maintain. Fortunately, Spring Boot provides a much cleaner solution through the @Valid annotation.

In this article, I'll explain how @Valid works, why it's useful, and how you can use it to build cleaner and more reliable REST APIs.


Why Do We Need Validation?

Let's assume we are building an Employee Registration API.

A user sends the following request:

{
  "name": "",
  "email": "sulochana",
  "age": 15
}

Clearly, this data is not valid:

  • Name should not be empty.

  • Email format is incorrect.

  • Age should meet business requirements.

Without validation, this incorrect data may reach the database and create unnecessary problems later. This is where Spring Boot validation helps us.

What is @Valid?

The @Valid annotation tells Spring Boot to validate an incoming object before executing the controller logic.

If any validation rule fails, Spring Boot automatically throws an exception and returns validation errors to the client.

Instead of writing manual validation code, we can simply define rules using annotations.

Adding Validation Dependency

To use validation in Spring Boot, add the following dependency to your Maven project:

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

Once this dependency is added, Spring Boot can process validation annotations automatically.

Creating a Request DTO

Let's create an EmployeeRequest class.

public class EmployeeRequest {

    @NotBlank(message = "Employee name is required")
    private String employeeName;

    @Email(message = "Please enter a valid email")
    private String email;

    @Min(value = 18, message = "Age must be at least 18")
    private Integer age;

    // Getters and Setters
}

Here we are defining validation rules directly on the fields.

Whenever a request arrives, Spring Boot checks these conditions before processing the request.

Understanding Common Validation Annotations

@NotNull

Use this annotation when a field must not be null.

@NotNull(message = "Id cannot be null")
private Long id;

This ensures that the field always contains a value.

@NotBlank

This is commonly used for String fields.

@NotBlank(message = "Name cannot be blank")
private String name;

It rejects:

  • null values

  • empty strings

  • strings containing only spaces

This is usually the preferred choice for names and text fields.

@NotEmpty

@NotEmpty(message = "Department cannot be empty")
private String department;

It checks whether a value exists but does not trim whitespace like @NotBlank.

@Email

@Email(message = "Invalid email format")
private String email;

This validates email structure automatically.

@Size

@Size(min = 3, max = 20,
      message = "Name should contain 3 to 20 characters")
private String name;

Useful when you want to control the length of user input.

@Pattern

@Pattern(
    regexp = "^[0-9]{10}$",
    message = "Mobile number must contain exactly 10 digits"
)
private String mobileNumber;

This annotation is very useful for validating phone numbers, PAN numbers, passwords, and other custom formats.

@Min and @Max

@Min(value = 18)
@Max(value = 60)
private Integer age;

These annotations define the acceptable numeric range.

Using @Valid in Controller

Now let's see where the actual validation happens.

@RestController
@RequestMapping("/employees")
public class EmployeeController {

    @PostMapping
    public ResponseEntity<String> createEmployee(
            @Valid @RequestBody EmployeeRequest request) {

        return ResponseEntity.ok("Employee Created Successfully");
    }
}

Notice the @Valid annotation before @RequestBody.

This single annotation tells Spring Boot to validate the incoming request.

If validation succeeds, the API executes normally.

If validation fails, Spring Boot throws a validation exception automatically.

What Happens When Validation Fails?

Suppose a client sends the following request:

{
  "employeeName": "",
  "email": "invalid-email",
  "age": 15
}

Spring Boot will detect multiple validation failures.

Instead of saving incorrect data, it returns validation errors immediately.

This protects our application from bad input data.

Customizing Validation Error Responses

The default validation response is often too detailed and not very user-friendly.

In real-world applications, we usually create a global exception handler.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>>
        handleValidationException(
        MethodArgumentNotValidException ex) {

        Map<String, String> errors = new HashMap<>();

        ex.getBindingResult()
          .getFieldErrors()
          .forEach(error ->
              errors.put(
                  error.getField(),
                  error.getDefaultMessage()
              ));

        return ResponseEntity.badRequest().body(errors);
    }
}

Now the client receives cleaner error messages that are easier to understand.

Nested Object Validation

In many projects, request objects contain child objects.

For example, an Employee may have an Address object.

public class Address {

    @NotBlank
    private String city;

    @NotBlank
    private String state;
}
public class EmployeeRequest {

    @NotBlank
    private String employeeName;

    @Valid
    private Address address;
}

Notice that we used @Valid again on the Address object.

Without it, Spring Boot validates only the EmployeeRequest fields and ignores Address validations.

Common Mistakes Developers Make

Forgetting @Valid in Controller

@PostMapping
public ResponseEntity<String> save(
        @RequestBody EmployeeRequest request)

In this case, validation will not run at all.

Always remember to add @Valid.

Missing Validation Dependency

If the validation starter dependency is missing, annotations such as @NotBlank and @Email will not work.

Using @NotNull for String Validation

Many beginners write:

@NotNull
private String name;

This still allows empty strings.

For text fields, @NotBlank is usually the better option.

Conclusion :

Validation is one of those things that developers sometimes overlook in the beginning, but it becomes extremely important as applications grow. Accepting invalid data can lead to unexpected errors, poor user experience, and even data integrity issues.

Whether you're building a simple CRUD application or a large-scale enterprise system, proper input validation should always be part of your development process. By combining @Valid with annotations like @NotBlank, @Email, @Size, and global exception handling, you can create cleaner, more maintainable, and more reliable APIs.

In the next article, I'll explore Spring Security Basics where I'll learn about Authentication, Authorization, and Security Configuration in Spring Boot applications.

I hope this article helped you understand how validation works in Spring Boot. If you're already using @Valid in your projects or have any questions, feel free to share your thoughts in the comments.

Comments

Popular posts from this blog

React Basics – How to Create Component

How to Build REST API using Spring Boot (Step-by-Step Guide)

Spring Boot @RequestParam Annotation Explained with Real-Time Examples