DEV Community

realNameHidden
realNameHidden

Posted on

How Do You Validate Query Parameters in Spring Boot?

Introduction

Imagine booking a movie ticket online.

If you accidentally enter -2 tickets or leave the city name empty, the system immediately shows an error—before proceeding further.

That early check is called validation.

In REST APIs, query parameters are often used for filtering, searching, and pagination. If these values are invalid and you don’t validate them properly, your API may behave unpredictably or even crash.

In this blog, you’ll learn how to validate query parameters in Spring Boot, explained in simple language, with end-to-end Java 21 examples, complete with cURL requests and responses.


Core Concepts

What Does “Validating Query Parameters” Mean?

Validating query parameters means:

  • Ensuring required parameters are present
  • Checking values are within acceptable limits
  • Rejecting bad input early with clear error messages

Example:


/products?page=-1&size=0

Enter fullscreen mode Exit fullscreen mode

Without validation → ❌ broken logic

With validation → ✅ clean 400 BAD_REQUEST


Key Annotations Used

Spring Boot uses Jakarta Bean Validation:

Annotation Purpose
@NotBlank String must not be empty
@Min / @Max Numeric range validation
@Pattern Regex-based validation
@Validated Enables validation for query params

⚠️ Important:

For query parameters, @Validated is mandatory.

Without it, validation will not trigger.


Why Validate Query Parameters?

✅ Prevent invalid requests

✅ Improve API reliability

✅ Protect business logic

✅ Provide clear client feedback

✅ Reduce production bugs


Code Examples (End-to-End)


✅ Example 1: Validate Pagination Query Parameters

Use Case

Fetch products with pagination.


Step 1: REST Controller

package com.example.demo.controller;

import jakarta.validation.constraints.Min;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/products")
@Validated // 🔴 REQUIRED for query param validation
public class ProductController {

    /**
     * Example:
     * /products?page=1&size=10
     */
    @GetMapping
    public String getProducts(
            @RequestParam
            @Min(value = 0, message = "Page must be 0 or greater")
            int page,

            @RequestParam
            @Min(value = 1, message = "Size must be at least 1")
            int size) {

        return "Fetching products [page=" + page + ", size=" + size + "]";
    }
}
Enter fullscreen mode Exit fullscreen mode
import java.time.OffsetDateTime;
import java.util.Map;

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

import jakarta.validation.ConstraintViolationException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<Map<String, Object>> handleMissingParams(MissingServletRequestParameterException ex) {

        return ResponseEntity.badRequest()
                .body(Map.of("status", 400, "error", "Bad Request", "message", ex.getParameterName() + " is required"));
    }

    // 🔹 Validation failure (@NotBlank, @Pattern, etc.)
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Map<String, Object>> handleConstraintViolation(ConstraintViolationException ex) {

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("timestamp", OffsetDateTime.now(), "status",
                400, "error", "Bad Request", "message", ex.getMessage(), "path", "/users"));
    }

}

Enter fullscreen mode Exit fullscreen mode

Step 2: Test with cURL

✅ Valid Request

curl "http://localhost:8080/products?page=1&size=10"
Enter fullscreen mode Exit fullscreen mode

✅ Response

Fetching products [page=1, size=10]
Enter fullscreen mode Exit fullscreen mode

❌ Invalid Request

curl "http://localhost:8080/products?page=-1&size=0"
Enter fullscreen mode Exit fullscreen mode

❌ Response

{
  "status": 400,
  "error": "Bad Request",
  "message": "Page must be 0 or greater"
}
Enter fullscreen mode Exit fullscreen mode

✔ Invalid input rejected early
✔ Clean HTTP status
✔ No controller clutter


✅ Example 2: Validate String Query Parameters

Use Case

Search users by role and status.


Step 1: Controller with String Validation

package com.example.demo.controller;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

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

    /**
     * Example:
     * /users?role=ADMIN&status=ACTIVE
     */
    @GetMapping
    public String getUsers(
            @RequestParam
            @NotBlank(message = "Role is required")
            @Pattern(
                regexp = "ADMIN|USER",
                message = "Role must be ADMIN or USER"
            )
            String role,

            @RequestParam(required = false)
            @Pattern(
                regexp = "ACTIVE|INACTIVE",
                message = "Status must be ACTIVE or INACTIVE"
            )
            String status) {

        return "Fetching users [role=" + role + ", status=" + status + "]";
    }
}
Enter fullscreen mode Exit fullscreen mode
import java.time.OffsetDateTime;
import java.util.Map;

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

import jakarta.validation.ConstraintViolationException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<Map<String, Object>> handleMissingParams(MissingServletRequestParameterException ex) {

        return ResponseEntity.badRequest()
                .body(Map.of("status", 400, "error", "Bad Request", "message", ex.getParameterName() + " is required"));
    }

    // 🔹 Validation failure (@NotBlank, @Pattern, etc.)
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Map<String, Object>> handleConstraintViolation(ConstraintViolationException ex) {

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("timestamp", OffsetDateTime.now(), "status",
                400, "error", "Bad Request", "message", ex.getMessage(), "path", "/users"));
    }

}

Enter fullscreen mode Exit fullscreen mode

Step 2: Test with cURL

✅ Valid Request

curl "http://localhost:8080/users?role=ADMIN&status=ACTIVE"
Enter fullscreen mode Exit fullscreen mode

✅ Response

Fetching users [role=ADMIN, status=ACTIVE]
Enter fullscreen mode Exit fullscreen mode

❌ Invalid Role

curl "http://localhost:8080/users?role=GUEST"
Enter fullscreen mode Exit fullscreen mode

❌ Response

{
  "status": 400,
  "error": "Bad Request",
  "message": "Role must be ADMIN or USER"
}
Enter fullscreen mode Exit fullscreen mode

❌ Missing Required Parameter

curl "http://localhost:8080/users"
Enter fullscreen mode Exit fullscreen mode

❌ Response

{
  "status": 400,
  "error": "Bad Request",
  "message": "Role is required"
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Always use @Validated on controllers
    Without it, query parameter validation won’t work.

  2. Validate at the boundary
    Reject bad input before it reaches business logic.

  3. Use meaningful validation messages
    Clients should understand what went wrong.

  4. Keep query params simple
    Complex validation may indicate a request body is better.

  5. Do not use validation annotations on @RequestParam without testing
    Missing parameters behave differently than request bodies.


Common Mistakes to Avoid

❌ Forgetting @Validated
❌ Assuming @Valid works for query parameters
❌ Catching validation exceptions inside controllers
❌ Using vague error messages
❌ Skipping validation for “small” parameters


Conclusion

Validating query parameters is a critical skill for building robust Spring Boot APIs.

With:

  • @Validated
  • Bean Validation annotations
  • Clean controller design

you can ensure your APIs fail fast, fail safely, and communicate clearly.

Mastering validating query parameters in Spring Boot will strengthen your Java programming foundation and help you learn Java with real-world backend best practices.


Call to Action

💬 Have questions about validation or error handling?
👇 Drop them in the comments below!


🔗 Helpful Resources


Enter fullscreen mode Exit fullscreen mode

Top comments (0)