@RequestParam

Binds a query string or form parameter to a method parameter, with defaults, optional values and type conversion.

Signature
@RequestParam(name = "page", defaultValue = "0") int page
  • Added in Spring Boot Spring Framework 2.5

Parameters

ParameterTypeDescription
$valueoptionalString= ""Alias for name.
$nameoptionalString= ""The parameter name in the request. Defaults to the Java parameter name (needs -parameters, which Spring Boot's build plugins enable).
$requiredoptionalboolean= trueWhether the parameter must be present. Missing required parameters give 400. Optional<T> parameters are treated as not required.
$defaultValueoptionalString= noneValue used when the parameter is missing or empty. Setting it implicitly makes the parameter not required.

Return value

n/aBinds a request parameter (query string or form field) to the parameter, converting it to the parameter type. Lists receive repeated values; Map and MultiValueMap receive every parameter.

Errors

Missing required parameter gives 400 (MissingServletRequestParameterException); a value that cannot be converted gives 400 (MethodArgumentTypeMismatchException).

@RequestParam reads a named parameter from the query string (?city=York) or from a URL-encoded form body. Use it for things that shape a response rather than identify a resource: filters, search terms, sorting, page number and size.

Required, optional and defaults

A plain @RequestParam String city is required: if the client leaves it out, Spring answers 400 before your method runs. There are three ways to make it optional, and they behave differently:

  • defaultValue = "20": missing or empty values become 20. Best for page sizes and flags.
  • Optional<String>: you get Optional.empty() and decide in code.
  • required = false: you get null. This fails on primitives such as int, because null cannot be assigned; use a wrapper type or a default.
@GetMapping("/api/hotels")
List<Hotel> search(@RequestParam String city,
                   @RequestParam(defaultValue = "1") int minStars,
                   @RequestParam Optional<String> sort,
                   @RequestParam(name = "amenity", required = false) List<String> amenities)

Types

Values are converted with the same conversion service as path variables. Repeated parameters (?amenity=pool&amenity=spa) bind to a List; Spring also splits a single comma-separated value into a list. Dates need @DateTimeFormat or a global spring.mvc.format.date setting so everyone agrees on the format; ISO yyyy-MM-dd is the safe choice.

Validation

Put Bean Validation constraints such as @Min and @Max directly on the parameter. With the validation starter present, Spring MVC's built-in method validation checks them and answers 400 with the violations. Always cap page sizes: ?size=1000000 is a cheap way to knock over a database.

Mistakes people make

  • Using @RequestParam for JSON bodies. It reads query and form parameters only; JSON needs @RequestBody.
  • Passing secrets or tokens in the query string. They end up in access logs and browser history.
  • Binding a Map<String, String> for filters and losing repeated values. Use MultiValueMap.

Example

Example · java
import java.util.List;
import java.util.Optional;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

record Hotel(long id, String city, int stars) {}

@RestController
public class HotelSearchController {

    private final List<Hotel> hotels = List.of(
            new Hotel(1, "York", 4), new Hotel(2, "York", 3), new Hotel(3, "Bath", 5));

    // GET /api/hotels?city=York&minStars=4&amenity=pool&amenity=spa
    @GetMapping("/api/hotels")
    List<Hotel> search(@RequestParam String city,                         // required: missing gives 400
                       @RequestParam(defaultValue = "1") int minStars,    // optional with a default
                       @RequestParam Optional<String> sort,               // optional, no default
                       @RequestParam(name = "amenity", required = false) List<String> amenities) {
        return hotels.stream()
                .filter(h -> h.city().equalsIgnoreCase(city))
                .filter(h -> h.stars() >= minStars)
                .toList();
    }
}

When to use it

  • Searching hotels by city with an optional minimum star rating
  • Paging through events with a capped page size
  • Filtering a product list by several colours at once

Frequently asked questions

What is the difference between @RequestParam and @PathVariable?

@PathVariable reads a segment of the path and usually identifies a resource. @RequestParam reads the query string or form data and usually filters or shapes the result.

Does defaultValue apply to an empty value like ?size=?

Yes. An empty value is treated like a missing one when a defaultValue is set.

More examples

Validating page and size

Constraint annotations on @RequestParam parameters are checked by Spring MVC's built-in method validation. Violations raise HandlerMethodValidationException, which becomes a 400 response.

Example · java
import java.util.List;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

record Event(long id, String name) {}

@RestController
public class EventController {

    // Constraints directly on parameters trigger Spring's built-in method
    // validation: size=5000 gives 400 before the method runs.
    @GetMapping("/api/events")
    List<Event> list(@RequestParam(defaultValue = "0") @Min(0) int page,
                     @RequestParam(defaultValue = "20") @Min(1) @Max(100) int size) {
        return List.of(new Event((long) page * size + 1, "Meetup"));
    }
}

Dates in the query string

@DateTimeFormat(iso = DATE) pins the format to yyyy-MM-dd. Without it, the accepted format depends on configuration and clients guess.

Example · java
import java.time.LocalDate;
import java.util.Map;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AvailabilityController {

    // GET /api/availability?from=2026-11-02&to=2026-11-05
    @GetMapping("/api/availability")
    Map<String, Object> availability(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
                                     @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
        return Map.of("from", from, "to", to, "nights", to.toEpochDay() - from.toEpochDay());
    }
}

All parameters at once

A MultiValueMap<String, String> receives every query parameter with all of its values. It suits dynamic filter screens where the allowed names come from data rather than code; check each name against that list before it reaches a query, and never build SQL from the names or values.

Example · java
import java.util.List;
import java.util.Map;

import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FilterController {

    // Every parameter, for dynamic filters such as ?colour=red&colour=blue&size=M.
    // A plain Map keeps only the first value of each name; MultiValueMap keeps all.
    @GetMapping("/api/products/filter")
    Map<String, List<String>> filter(@RequestParam MultiValueMap<String, String> params) {
        return Map.copyOf(params);
    }
}

Discussion

  • Be the first to comment on this lesson.