In this article, we will understand the usage of @PathVariable
annotation in Spring. This is a very commonly used annotation when creating a web application.
This web application may be an MVC application or a REST web service. Also, this article is relevant for Spring and Spring boot applications both.
Suppose you have a URL of below form
http://localhost:8080/user/12
Here,
1. URL till http://localhost:8080/user
is a resource URL that is used to fetch a resource, a user in this case,
2. URL portion after this is used to identify the resource, in this case, it might be a user with id 12. This part is dynamic and its value may vary for different requests.
In a Spring application, how would you retrieve the dynamic value in the request URL, it is where @PathVariable
annotation comes handy.
Scenario
In order to handle URLs that map to a resource such as that shown in the previous section, you need to create a method in a Spring controller which looks as below.
@GetMapping("/user/{id}") public User getUser(Integer userId) { // fetch user }
Here, the dynamic part is enclosed between curly braces. Its name need not be id
, it can be any string.
It is called path variable or template variable as shown below.
Any request of the format http://<approot>/user/<something>
will be handled by this controller method.
Now, how do you get the value of template variable from the request URL inside the controller method. This is where @PathVariable
comes into picture.
@PathVariable
annotation is applied before a method argument and it populates the argument with the value sent in the URL parameter.@PathVariable
accepts a String argument which matches with the template variable given in the controller URL enclosed between curly braces as shown in the below image.@PathVariable
binds the method variable that follows it with the value in the request URL.@PathVariable example
Below is an example of
@PathVariable
annotation.
@GetMapping("/user/{id}") public User getUser(@PathVariable("id") Integer userId) { // fetch user }
In above example, userId
variable is populated with the value in request URL after /user
.
So, for the URL, http://localhost:9090/user/12
, the variable userId
will be populated with 12.
@PathVariable("id")
can also be written as @PathVariable(name="id")
or @PathVariable(value = "id")
since name
and value
are the attributes of @PathVariable
.
Omitting @PathVariable argument
Argument supplied to @PathVariable
can be omitted if the template variable in controller URL matches with the method argument annotated with @PathVariable
.
Example,
@GetMapping("/user/{id}") public User getUser(@PathVariable Integer id) { // fetch user }
In this example, @PathVariable
does not have any argument since the controller method parameter(annotated with @PathVariable
) and template variable are the same.
A controller URL may be of the format,
http://localhost:8080/app/user/{id}/{name}
.This URL contains two template variables and we need to assign them to different method arguments.
So, we can write a controller method with more than one @PathVariable
annotations as shown below.
@GetMapping("/user/{id}/{name}") public User getUser(@PathVariable Integer id, @PathVariable String name) { // fetch user on id and name }
Map all template variables
There may be multiple template variables such as in the example above.
Instead of defining method arguments for each template variable and annotating them with @PathVariable
, we can define a java.util.Map<String, String>
and it will automatically be populated with all template variables and their values as its key and value respectively, when the request arrives.
Example,
@GetMapping("/user/{uid}/{uname}") public User getUser(@PathVariable Map<String, String> map) { String id = map.get("uid"); String name="map.get("uname") // fetch user on id and name }
If the request URL is http://localhost:8080/appname/12/abc
, then id
will be “12” and name
will be “abc”.
Optional template variable
A controller URL of the form /user/{id}
will only accept requests that end with /user/something
.
That is, it is mandatory to supply path variable in the incoming request or else it will fail with a 404 Not Found error.
However, this can be avoided using required
attribute of @PathVariable
as shown below.
@GetMapping("/user/{name}") public User getUser(@PathVariable(required = false) String name) { // fetch user }
Now, this method can handle requests of the form
http://localhost:8080/appname/user
, and
http://localhost:8080/appname/user/12
.
Default value of required
is true
.
Using Java 8 optional
There is another method of specifying optional path variables apart from required
attribute. It is by using Java 8 optional.
Simply make the type of method argument java.util.Optional
as shown below.
@GetMapping("/user/{name}") public User getUser(@PathVariable Optional<String> name) { // fetch user }
@PathVariable
are of immense use when designing api in a Spring application since they easily map dynamic request URLs to controller methods.That was all on this annotation. Hope the article was useful and informative.