Building RESTful APIs with Spring Boot
Explore the creation of RESTful services using Spring Boot.
Content
Path Variables and Query Parameters
Versions:
Watch & Learn
AI-discovered learning video
Spring Boot Path Variables and Query Parameters: The Art of Getting What You Asked For
If REST endpoints are conversations, then path variables and query parameters are how you stop mumbling and actually say what you mean.
You’ve already spun up controllers and sworn fealty to REST principles. Great. Now let’s teach your endpoints to listen closely and respond like they’ve had espresso and therapy. Today’s focus: how Spring Boot handles path variables and query parameters — the difference between “show me that exact thing” and “filter the universe for this vibe.”
What Are Path Variables and Query Parameters?
- Path variables identify a specific resource. Think:
/users/42— that’s not a suggestion. That’s The One User. - Query parameters refine, sort, paginate, or search collections. Think:
/users?status=active&page=2&size=20— bring me the active ones, but gently, and in pages.
Analogy time:
- Path variable = a street address. You knock on a specific door.
- Query parameter = a grocery list note. “Get apples (preferably Granny Smith), and if they’re out, vibes are ruined.”
Quick Comparison
| Aspect | Path Variable | Query Parameter |
|---|---|---|
| Purpose | Identify a single resource (or nested resource) | Filter/sort/paginate a collection |
| Example | /orders/123 |
/orders?status=SHIPPED&sort=date,desc |
| Caching | Highly cacheable (stable resource URI) | Cacheable if the query is consistent |
| Semantics | Noun (the thing) | Adjectives/adverbs (how to get the thing) |
How Do Path Variables and Query Parameters Work in Spring Boot?
We’ll stand on the shoulders of your earlier REST controllers. Same annotations, more precision.
Path Variables with @PathVariable
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
// IDs must be digits: regex in the URI template
@GetMapping("/{id:\\d+}")
public UserDto getUserById(@PathVariable long id) {
// fetch and return
return userService.findById(id);
}
// Nested resource: a user's orders
@GetMapping("/{userId}/orders")
public List<OrderDto> getUserOrders(@PathVariable("userId") long id) {
return orderService.findByUserId(id);
}
}
Notes:
- You can bind to types like
UUID,Long,String, etc. - You can add regex to constrain the path variable:
/{id:\\d+}. - Name your variables clearly. Your future self will buy you coffee.
Query Parameters with @RequestParam
@GetMapping
public Page<UserDto> findUsers(
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
@RequestParam(required = false) List<String> tags // ?tags=pro&tags=new
) {
return userService.search(status, page, size, tags);
}
Notes:
required = falsemakes parameters optional.defaultValue = "..."provides a fallback.List<String>lets you capture repeated params like?tags=a&tags=b.
Grabbing All Query Parameters (Power Move)
@GetMapping("/debug")
public Map<String, String> debugParams(@RequestParam Map<String, String> allParams) {
return allParams; // echo everything for troubleshooting
}
Or if you expect repeated keys:
@GetMapping("/search")
public List<ProductDto> search(@RequestParam MultiValueMap<String, String> params) {
// params.get("tag") -> ["sale", "new"]
return searchService.search(params);
}
Dates, Formats, and Fancy Types
@GetMapping("/{id}/activity")
public List<ActivityDto> activity(
@PathVariable UUID id,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to
) {
return activityService.findBetween(id, from, to);
}
Spring handles conversion for many types out of the box. For custom types, register a Converter.
Binding Query Parameters to an Object (Chef’s Kiss)
public record UserFilter(
String status,
@Min(0) Integer page,
@Min(1) @Max(100) Integer size
) {}
@GetMapping("/v2")
public Page<UserDto> list(@Valid @ModelAttribute UserFilter filter) {
return userService.search(filter.status(), filter.page(), filter.size(), null);
}
Micro-lesson: Spring treats GET request parameters as a
@ModelAttributeby default. You can bind them into a record/POJO and validate like a civilized human.
Examples of Path Variables and Query Parameters in Real APIs
- Get a specific product (path variable):
curl http://localhost:8080/api/products/987
- Search products (query params):
curl "http://localhost:8080/api/products?q=keyboard&sort=price,asc&page=1&size=50"
- Filter with multiple tags and a date range:
curl "http://localhost:8080/api/products?tag=mechanical&tag=rgb&from=2024-01-01&to=2024-12-31"
- Nested resource + filters combo:
curl "http://localhost:8080/api/users/42/orders?status=SHIPPED&page=0&size=10"
You see the pattern: path says “which box,” query says “how to sort what’s in the box.”
Why Do Path Variables and Query Parameters Matter in Microservices?
- Contracts are everything. Consistent use of path variables vs query parameters makes your API predictable and discoverable.
- Caching & performance. Stable resource URLs (with path variables) are cache-friendly. Queries can be cached too if you standardize them.
- Gateway rules & observability. API gateways can route/limit based on paths. Logs and metrics become legible instead of cryptic soup.
- Idempotence & safety. GET + query parameters = safe reads. Don’t mutate state with them unless you like chaos.
“Clear URIs turn distributed systems from spider webs into subway maps.” — someone who’s been paged at 3 a.m.
Common Mistakes in Path Variables and Query Parameters (And How to Fix Them)
- Name mismatch between URI template and @PathVariable
@GetMapping("/{userId}")
public UserDto get(@PathVariable("id") Long userId) { ... } // ❌
- Fix: make them match.
@GetMapping("/{userId}")
public UserDto get(@PathVariable Long userId) { ... } // ✅
- Using query params to identify a single resource
GET /users?id=42— meh. Not wrong, but it signals “filtering,” not “identity.” Prefer/users/42.
- Forgetting URL encoding
?q=java springwill split as two tokens. Use?q=java%20springor let your HTTP client encode it.
- Ambiguous mappings
@GetMapping("/{id}")
@GetMapping("/search")
// If not careful, /search can collide if {id} accepts letters.
- Fix: constrain
idwith regex or separate paths like/by-id/{id}.
- Missing defaults or wrong
required
@GetMapping
public Page<UserDto> list(@RequestParam int page) { ... } // ❌ 400 if page not provided
- Fix:
@RequestParam(defaultValue = "0") int pageorrequired=falsewith sensible handling.
- Not validating inputs
- Paging params without
@Min, enums without checking allowed values = production sadness.
- Leaking sensitive data in query parameters
- Tokens in the query string land in logs and browser history. Use headers or request bodies for sensitive stuff.
- Returning 200 for a missing path resource
GET /users/9999should be404 Not Found, not an empty user with vibes.
Pro Moves: Make Your URLs Do Pilates
- Build safe links programmatically:
URI location = UriComponentsBuilder
.fromPath("/api/users/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).build();
- Document your contract with OpenAPI/Swagger. Be explicit about path variables and query params:
@Operation(summary = "Find users", parameters = {
@Parameter(name = "status", description = "Filter by status", in = ParameterIn.QUERY),
@Parameter(name = "page", description = "Zero-based page index", in = ParameterIn.QUERY)
})
- Prefer collections + query params for search endpoints and path variables for singletons. Your API reads like English — and that’s the point.
TL;DR and Takeaways
- Use path variables for identity:
/users/42. - Use query parameters for filtering/sorting/pagination:
/users?status=active&page=0&size=20. - Spring Boot makes both stupid-easy with
@PathVariableand@RequestParam(plusList,Map,MultiValueMap, and object binding with@ModelAttribute). - Validate everything:
@Min,@Max, regex in URI templates, and type-safe conversions. - Be consistent; your future microservices (and sleep schedule) depend on it.
The endpoint is a sentence. Path variables are the nouns. Query parameters are the adjectives. Make good grammar, ship better software.
And that’s how you master Spring Boot Path Variables and Query Parameters without summoning chaos demons. Up next: error handling that doesn’t gaslight your clients.
Comments (0)
Please sign in to leave a comment.
No comments yet. Be the first to comment!