Spring @PathVariable and @RequestParam

Learn about Spring @PathVariable and @RequestParam annotations and compare them with Jakarta’s @PathParam and @QueryParam annotations.

Spring Framework

In Spring, @PathVariable binds a value from the URL path to a method parameter, whereas @RequestParam binds a query parameter. The equivalent annotations in Java/Jakarta EE are @PathParam and @QueryParam. This article also covers the encoding of parameter values and how to make the parameters optional.

1. Passing Parameters in URLs

A URL can contain two types of request parameters, namely path parameters and query parameters. Here’s an example of a URL that includes both.

http://localhost:8080/users/{id}/accounts?type=current&status=active

In the example URL, we have the following parameters.

  • id is the path parameter
  • type and status are the query parameters

2. Spring @PathVariable and @RequestParam Annotations

Spring accepts path variables with @PathVariable and query parameters with @RequestParam.

@GetMapping("/users/{id}/accounts")
public List<Accounts> getAccounts(@PathVariable String id, @RequestParam String type, @RequestParam String status) {

    //...
}

The following request shows how Spring populates the request parts into the method arguments of the handler method.

  • The @PathVariable extracts the URI template variables from the request URL. For example, in the URI template “/users/{id}/accounts”, the value of id is mapped to a value 101. In runtime, the method parameter id is initialized with the value 101 for this reason.
  • The @RequestParam extracts the query parameters, form parameters, and even files from the request. In our example, we have two query parameters, type and status. Any value passed in these parameters will be used to initialize the method arguments type and status.

We can pass both dynamic values in the URL path and additional parameters as query parameters to give the server more information about the request.

If the same query parameter is passed multiple times in a URL then the first value (lexically) of the parameter is used.

2.1. Naming Method Variables Different from URI Template Variables

In the previous example, we didn’t define the name of the path variable since the names of the method parameter and the path variable were the same. However, if the path variable name is different from the URI template variable, we must provide the name in the @PathVariable annotation:

In the following handler method, we are mapping the id path variable to userId method parameter. 

@GetMapping("/user/{id}")
public String getUserById(@PathVariable(name = "id") String userId) {
    //...
}

Similarly, @RequestParam name also can be configured using the name attribute. In the following example, any query parameter sent with ‘?name=‘ will be populated into username variable.

@GetMapping("/users")
public String getUsers(@RequestParam(name = "name") String username) {
    //...
}

2.2. Collecting Multiple Parameters and Values in a Map

Consider the URL http://localhost:8080/users/{id}/{name}/accounts?type=current&status=active. A complex API can have many path variables and query parameters. The client may also not send all the parameters in each request, so many variables stay unused in a request.

When an API has more than one path variable and request parameter, we can use a Map to collect the parameters and values instead of naming each parameter individually.

//Example URL: /users/location/IN/region/DEL?status=active&minAge=18&maxAge=60

@GetMapping("/users/country/{countryCode}/state/{stateCode}")
public String getUsers(@PathVariable Map<String, String> locationMap, @RequestParam Map<String,String> queryMap) {

    //...
}

In the above example, if we invoke the URL /users/location/IN/region/DEL?status=active&minAge=18&maxAge=60, the maps contain the following values.

  • locationMap => [countryCode=IN, stateCode=DEL]
  • queryMap => [status=active, minAge=18, maxAge=60]

3. Support for Optional Parameters

3.1. Using Attribute ‘require= false‘

By default, all the method parameters annotated with @RequestParam and @PathVariable are required. To make a @PathVariable or @RequestParam parameter optional, we set the required attribute to false. Its default value is true.

In the following example, passing both query parameters, type and status, is optional.

@GetMapping("/user/{id}")
public String getAccounts(@PathVariable String id, 
  @RequestParam(required = false) String type, 
  @RequestParam(required = false)  String status) {

    //...
}

3.2. Using Java 8 Optional

Alternatively, we can use java.util.Optional to handle a non-mandatory path variable or request params. The Optional class lets us either throw an error or provide a default value if the value is missing.

The same example with Optional looks as follows.

@GetMapping("/user/{id}")
public String getAccounts(@PathVariable Optional<String> String id, 
  @RequestParam Optional<String> type, 
  @RequestParam Optional<String> status) {
    
    String userId = id. orElseThrow(...);
    String userType = type.orElseGet(() -> "GUEST");
    //...
}

4. Setting Default Values

Spring has no built-in default value for method parameters annotated with @PathVariable. However, java.util.Optional tells us whether the path variable holds a value, and when it is empty we provide a default value, as shown in the previous section.

However, for method parameters annotated with @RequestParam we can use the defaultValue attribute as a fallback when the parameter is not provided or has an empty value. The defaultValue attribute also makes a parameter optional (required = false).

Consider a URL http://localhost:8080/users?pageNo=1&pageSize=20. We can set a default value for pageNo and pageSize parameters as shown below.

@GetMapping("/users")
public String getAllUsers(@RequestParam(value = "pageNo", defaultValue = "0") int pageNo,
            @RequestParam(value = "pageSize", defaultValue = "30") int pageSize) {

    //...
}

5. Passing Encoded vs Exact Values to Parameters

The value of @PathVariable parameter is extracted from the URI path so it cannot be not encoded. HTTP request paths cannot have encoded values.

For example, consider the URL http://localhost:8080/user/A%20BC. The controller method and the response are as follows.

@GetMapping("/user/{id}")
public String getUserById(@PathVariable String Id) {
    return "User Id: " + id;
}

---- response ----
User Id: A%20BC

The value is mapped to id parameter as it is without being decoded.

The value of @RequestParam parameters are encoded in the URL when sent, and the controller decodes it when it receives the request.

For example, the controller method and the response for the URL http://localhost:8080/users?name=John%20Doe are as follows.

@GetMapping("/users")
public String getUsers(@RequestParam String name) {
    return "Name: " + name;
}

---- response ----
Name: John Doe

Here the single space in the name “John Doe” is URL encoded to “%20” while sending the request to the server.

6. FAQs

6.1. What is the difference between @PathVariable and @PathParam?

Both, @PathParam and @PathVariable, annotations extract values from the URI path of a request URL. However, they are associated with different frameworks.

The @PathVariable annotation is used in the Spring Framework, while @PathParam annotation is used in the Java/Jakarta EE (Enterprise Edition) framework, specifically in JAX-RS, which is a specification for building RESTful web services in Java. It is available to use in frameworks that implement the specification, such as RESTEasy.

Here’s an example of how we would use @PathParam on a JAX-RS resource method.

@GET
@Path("/user/{id}")
public Response getUserById(@PathParam("id") String id) {

    // ...
}

6.2. What is the difference between @QueryParam and @RequestParam?

Both, @QueryParam and @RequestParam, bind the value(s) of an HTTP query parameter to a resource method parameter.

The @RequestParam annotation is part of the Spring Framework, while @QueryParam annotation is part of the JAX-RS specification and is available to use in frameworks that implement the specification.

Here’s an example of how @QueryParam can be used in JAX-RS.

@GET
@Path("/users")
public Response getUsers(@QueryParam("name") String name) {
    // Method implementation
}

7. Conclusion

In this Spring annotations tutorial, we learned the differences between @RequestParam and @PathVariable in capturing the request parameters and query parameters. We also learned about setting default values to parameters, making them optional as well as passing encoded vs exact values.

We also learned about @PathParam and @QueryParam and their usage.

Happy Learning !!

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.