skip to content

How do you capture a dynamic segment from a URL in a Spring MVC controller, and how do you read its value?

level: juniorimportance: must knowfreq 85%

answer

  1. Curly braces {id} in mapping
  2. @PathVariable binds it
  3. -parameters flag lets you drop the name
  4. Bad type = 400, no match = 404
  5. Required by default

basics

~10 s

Put a placeholder in curly braces in the mapping, like /users/{id}, then bind it with @PathVariable on a method parameter. Spring extracts that URL segment and passes it into your method.

solid answer

~40 s

You declare a URI template variable in the mapping path using curly braces — e.g. @GetMapping("/users/{id}"). Then a method parameter annotated @PathVariable("id") receives the captured value, converted to the parameter type (String, Long, UUID, etc.) via Spring's type conversion. If the parameter name matches the template name and you compile with -parameters, you can drop the explicit name: @PathVariable Long id. Multiple variables are fine: /orders/{orderId}/items/{itemId}. By default a @PathVariable is required — a missing value yields an error. You can make it optional with required=false (giving null) or by using Optional<T>. A common gotcha: type conversion failure (e.g. non-numeric id for Long) produces a 400 Bad Request, not a 404.

code

java · 16 lines
java
@RestController
@RequestMapping("/api")
public class OrderController {

    @GetMapping("/orders/{orderId}/items/{itemId}")
    public Item getItem(@PathVariable Long orderId,
                        @PathVariable Long itemId) {
        return service.find(orderId, itemId);
    }

    // Grab all template variables at once
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Map<String, String> vars) {
        return service.byId(vars.get("id"));
    }
}

go deeper

for a junior

Must know the {id} + @PathVariable pairing and how to read the value. Core everyday MVC skill.

for a middle

Should also know the 400-vs-404 distinction and the -parameters name-matching rule.

for a senior

Frames path variables vs query params as a resource-modeling choice; knows conversion pipeline and Optional/required semantics.

for a principal

Discusses API-design conventions, type-safety, and how binding failures surface to clients consistently across the codebase.

## What a path (URI template) variable is A **URI template variable** (also called a path variable) is a named placeholder inside a request mapping path, written in curly braces: `{id}`. When a request URL matches the pattern, Spring extracts the text occupying that segment and makes it available to your handler method. ```java @RestController public class UserController { @GetMapping("/users/{id}") public User get(@PathVariable Long id) { ... } } ``` For `GET /users/42`, Spring captures `42`, converts it to `Long`, and passes it in. ## The @PathVariable annotation `@PathVariable` binds a method parameter to a URI template variable. Key points: - **Name resolution**: `@PathVariable("id")` names the template explicitly. If you compile Java with the `-parameters` flag (Spring Boot enables this), the annotation name can be omitted and the parameter name is used: `@PathVariable Long id`. Without `-parameters`, the parameter name is lost at runtime and you must supply the name. - **Type conversion**: The captured string is converted to the declared type using Spring's `ConversionService` / registered `Converter`s and `Formatter`s. Built-in support covers `String`, all numeric types, `boolean`, `UUID`, enums, and anything with a registered converter. A conversion failure (e.g. `abc` for a `Long`) throws `MethodArgumentTypeMismatchException`, which resolves to **HTTP 400 Bad Request**. - **Required by default**: A `@PathVariable` is mandatory. Because the variable is part of the URL pattern itself, a truly absent segment usually means the URL didn't match at all (404). You can mark it `required = false` or use `Optional<T>`; this mainly matters when the same variable is optional across composed patterns. ## Multiple variables and a Map ```java @GetMapping("/orders/{orderId}/items/{itemId}") public Item item(@PathVariable Long orderId, @PathVariable Long itemId) { ... } ``` You can also grab all of them at once: ```java @GetMapping("/orders/{orderId}/items/{itemId}") public Item item(@PathVariable Map<String, String> vars) { String orderId = vars.get("orderId"); } ``` ## Common gotchas - **400 vs 404**: A wrong *type* (non-numeric for `Long`) is a 400. A URL that matches no pattern is a 404. Don't confuse them. - **Dots and slashes in values**: By default, the path is split on `/`, so a variable can't span multiple segments unless you use a wildcard pattern. Values containing dots historically caused truncation with suffix pattern matching; with modern `PathPattern` and suffix matching disabled by default this is a non-issue. - **Encoding**: `@PathVariable` values are URL-decoded before binding. ## When to use Use path variables for **resource identifiers** that are part of the resource hierarchy (`/users/42`). Use query parameters (`@RequestParam`) for filters, sorting, and optional criteria (`/users?active=true`).

  • What HTTP status results if a client calls /users/abc and the handler declares @PathVariable Long id?
    400 Bad Request. Spring can't convert 'abc' to Long, throwing MethodArgumentTypeMismatchException, which the default handler maps to 400 — not a 404.
  • When can you omit the name in @PathVariable id?
    When the code is compiled with the -parameters flag so the parameter name survives at runtime, and that name matches the template variable. Spring Boot enables -parameters by default.

context