Skip to content
Spring Boot sb web 3 min read

Path & Query Parameters

Most endpoints need to pull values out of the request: an id from the URL, filters from the query string, a token from a header. Spring MVC binds each of these declaratively with dedicated annotations. This page covers @PathVariable, @RequestParam, @RequestHeader, and @CookieValue, plus binding many params to a single object.

@PathVariable — values from the URL path

A @PathVariable binds a templated segment of the URL to a method parameter. The template name and the parameter name should match (or be named explicitly).

@GetMapping("/api/users/{id}")
public User byId(@PathVariable Long id) {
    return service.findById(id);
}

// Multiple variables, explicit names
@GetMapping("/api/users/{userId}/orders/{orderId}")
public Order order(@PathVariable("userId") Long userId,
                   @PathVariable("orderId") Long orderId) {
    return service.findOrder(userId, orderId);
}

Type conversion is automatic: {id} becomes a Long, a UUID, an enum, etc. A value that cannot convert produces 400 Bad Request.

Request:

curl http://localhost:8080/api/users/42

Output:

{ "id": 42, "name": "Ada Lovelace", "email": "[email protected]" }

@RequestParam — values from the query string

@RequestParam binds query-string parameters (and form fields). By default a request param is required.

@GetMapping("/api/products")
public List<Product> search(@RequestParam String category) { ... }

A missing required param returns 400 Bad Request. Make it optional with required = false or give it a defaultValue (which implies optional).

@GetMapping("/api/products")
public List<Product> search(
        @RequestParam(required = false) String category,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "20") int size) {
    return service.search(category, page, size);
}
SettingEffect
@RequestParam String qrequired; 400 if missing
@RequestParam(required = false)optional; null if missing
@RequestParam(defaultValue = "20")optional; uses default if missing
Optional<String> qoptional; empty if missing

Tip: Prefer defaultValue over required = false plus a null check — it removes a branch and documents the default in the signature.

Multiple values and maps

A repeated param binds to a List or array; an unknown set of params can bind to a Map.

// GET /api/products?tag=new&tag=sale
@GetMapping("/api/products")
public List<Product> byTags(@RequestParam List<String> tag) { ... }

// All query params at once
@GetMapping("/api/search")
public Results search(@RequestParam Map<String, String> filters) { ... }

Mapping many params to an object

When a handler has many filters, bind them to a POJO or record instead of a long parameter list. Spring populates fields from matching query params automatically — no annotation needed on the parameter.

public record ProductFilter(
        String category,
        BigDecimal minPrice,
        BigDecimal maxPrice,
        int page,
        int size) {}

@GetMapping("/api/products")
public List<Product> search(ProductFilter filter) {
    return service.search(filter);
}

Request:

curl "http://localhost:8080/api/products?category=books&minPrice=10&page=1&size=50"

Spring maps category, minPrice, page, and size onto the record components. Use @DateTimeFormat on fields when binding dates.

@RequestHeader — reading HTTP headers

@RequestHeader binds a header value. Like @RequestParam, it supports required and defaultValue.

@GetMapping("/api/profile")
public Profile profile(
        @RequestHeader("Authorization") String authHeader,
        @RequestHeader(value = "Accept-Language", defaultValue = "en") String lang) {
    return service.profileFor(authHeader, lang);
}

// All headers in one shot
@GetMapping("/debug/headers")
public Map<String, String> headers(@RequestHeader Map<String, String> headers) {
    return headers;
}

@CookieValue — reading cookies

@CookieValue binds a single cookie by name.

@GetMapping("/api/cart")
public Cart cart(@CookieValue(value = "SESSION", required = false) String sessionId) {
    return service.cartFor(sessionId);
}

Putting it together

@RestController
@RequestMapping("/api/articles")
public class ArticleController {

    private final ArticleService service;

    public ArticleController(ArticleService service) {
        this.service = service;
    }

    @GetMapping("/{id}")
    public Article one(
            @PathVariable Long id,
            @RequestParam(defaultValue = "false") boolean includeComments,
            @RequestHeader(value = "Accept-Language", defaultValue = "en") String lang) {
        return service.find(id, includeComments, lang);
    }
}

Request:

curl "http://localhost:8080/api/articles/7?includeComments=true" \
  -H "Accept-Language: fr"

Output:

{
  "id": 7,
  "title": "Liaison des paramètres",
  "language": "fr",
  "comments": [ { "id": 1, "text": "Très utile !" } ]
}

Pitfalls

  • An int/long param has no “absent” value — make it optional with a defaultValue or use a wrapper type / Optional.
  • Path variables containing special characters (slashes, dots) need care; use {*var} to capture trailing slashes.
  • Header names are case-insensitive in HTTP, but match the conventional casing for readability.
Last updated June 13, 2026
Was this helpful?