@RequestParam and @PathVariable in Spring Boot REST

@RequestParam and @PathVariable in Spring Boot REST | We will discuss how to pass request parameters to the rest APIs. To pass request parameters @RequestParam and @PathVariable are used in Spring. First, let us see @RequestParam.

@RequestParam in Spring Boot REST

Request Parameter format: URL?key=val&key=val&key=val….

  • Data is sent to the application using the URL in key = val format.
  • We can pass multiple key=val, it is not required to follow the order of parameters present in the method declaration.
  • To Read Data:-
@RequestParam("key") DataType localVariable
// or
// keyName and variable name are same
@RequestParam DataType key 

It even supports type conversion, (String -> int) based on the data type that you have provided. The default data type is String.

Many web apps are using RequestParam, even we can use same in webservices also.

https://www.google.com/search
? q=india
& oq=india
& aqs=chrome..69i57j46i275i433j0i131i433l3j0j69i60j69i65.2086j0j7
& sourceid=chrome
& ie=UTF-8

It internally uses the servlets concept.

@RequestParam("sid") Integer id

Servlets equivalent code:-

String sid = request.getParameter("sid");
Integer id = Integer.parseInt(sid);

Request Parameter Example:-

@RestController
public class ProductRestController {

    @GetMapping("/data")
    public String showData(@RequestParam Integer pid, @RequestParam String pcode,
                   @RequestParam Double pcost) {
        return "{ pid :" + pid + ", pcode: " + pcode + ", pcost: " + pcost + " }";
    }

}

URLs:-
http://localhost:8080/data?pid=10&pcode=PEN&pcost=300
http://localhost:8080/data?pcode=PEN&pcost=400&pid=101

Here the order of parameters are not important.

@RequestParam(required = false, defaultValue = “value”)

How can we make RequestParam from required to optional param? By default, RequestParam is required (i.e. required = true). In required = true, case if we did not send data then FrontController returns 404-Not Found. But if we want to make it optional, then we have to mention a default value. RequestParam can be make optional having some default value as:- @RequestParam(required = false, default="value") DataType localVarible. The default value must be passed as string.

@RestController
public class ProductRestController {

    @GetMapping("/data")
    public String showData(@RequestParam Integer pid, @RequestParam String pcode,
            @RequestParam(required = false, defaultValue = "100") Double pcost) {
        return "{ pid :" + pid + ", pcode: " + pcode + ", pcost: " + pcost + " }";
    }
}

URL:- http://localhost:8080/data?pid=10&pcode=PEN
Response:- { pid :10, pcode: PEN, pcost: 100.0 }

@PathVariable in Spring Boot REST

There are two types of paths:-

  • Static Path:- It indicates the location(Path) given to the resource(Controller#method). Example: /product/export, /employee/save .. etc.
  • Dynamic Path:- It indicates sending data along with the URL as PathType without any key(Direct Value). Example: /product/{id} , /employee/find/{code} Here /{ } indicates dynamic path(i.e. send data at runtime).

@PathVariable is used for dynamic paths.

  • PathVariables are also called clean URLs (No additional Symbols ? & as they are overloaded)
  • It must follow the order. It avoids confusion for other devs/users.
  • Execution is bit faster compared to @RequestParam.
  • URL size also gets reduced.

With Request Param:- http://localhost:8080/data?pid=10&pcode=PEN&pcost=300
With Path Variable:- http://localhost:8080/data/10/PEN/300

To read data in the application, syntax is:-

@PathVariable("key") DataType localVariable
// or
// keyName and variable name are same
@PathVariable DataType key

It even supports type conversion, (String -> int) based on the data type that you have provided. The default data type is String.

While adding Path in code, we must specify static and dynamic path details using @___Mapping("___") annotation.

3 Steps:-

  • Define Dynamic Path at Method Level. Example: @GetMapping("/employee/find/{eid}")
  • Read Path Variable data at Method Param. Example: @PathVariable Integer eid
  • Pass data using Request URL. Example: http://localhost:8080/employee/find/10

While making the request we must maintain the number of level counts in the code. It should be equal to URL Path levels. Example:-

In code: @GetMapping("/emp/find/data/{code}")
Request URLs:-

http://localhost:8080/emp/find/data/AValid
http://localhost:8080/emp/find/data/A/B404 – Not Found
http://localhost:8080/emp/find/data404 – Not Found

If we compare the above cases with @RequestParam:-

http://localhost:8080/emp/find/data?code=AValid
http://localhost:8080/emp/find/data?code=A&dec=BValid, Additional Param
http://localhost:8080/emp/find/data400 – Bad Request

Different Cases with @PathVariable in Spring Boot REST

Case#1:- Ambiguous handler methods

@GetMapping("/emp/find/{a}")
public String m1(@PathVariable String a) {
   // code
}

@GetMapping("/emp/find/{b}")
public String m1(@PathVariable String a) {
   // code
}

URL: http://localhost:8080/emp/find/ABC
Response: 500 – Internal Server Error. IllegalStateException: Ambiguous handler methods

Just because of name/datatype change in dynamic path, they are never going to be different URLs.

Case#2:- Multiple methods have the same request URL through static & dynamic path

If a Request URL is matched with multiple methods that are defined using PathVariables, then first priority is given to more static count levels. (static means letter to letter should be compared including case {case-sensitive} full path must be same). If not then come to the next level dynamic paths.

@RestController
public class ProductRestController {

    @GetMapping("/emp/mode/code")
    public String showA() {
        return "FROM#A";
    }

    @GetMapping("/emp/mode/{code}")
    public String showB(@PathVariable String code) {
        return "FROM#B " + code;
    }

    @GetMapping("/emp/{mode}/{code}")
    public String showC(@PathVariable String mode, @PathVariable String code) {
        return "FROM#C " + mode + "," + code;
    }

    @GetMapping("/{emp}/{mode}/{code}")
    public String showD(@PathVariable String emp, @PathVariable String mode, 
                @PathVariable String code) {
        return "FROM#D " + emp + ", " + mode + "," + code;
    }

}

If we call http://localhost:8080/emp/mode/code then which method is matched? The showA() method will be executed because the path ’emp/mode/code’ is matched.

We can even have paths with all dynamics(valid).

If we call http://localhost:8080/Emp/Mode/code then which method is matched? URL is case-sensitive. The showA(), showB(), showC() methods start with '/emp' but the URL contains '/Emp'. The showD() method starts with the dynamic path therefore it will be executed.

URLSelected Method
/emp/mode/xyzshowB()
/emp/xyz/xyzshowC()
/emp/Mode/codeshowC()
/emp/Mode/xyzshowC()
/xyz/xyz/xyzshowD()
/Emp/xyz/xyzshowD()
/Emp/Mode/xyzshowD()

If you enjoyed this post, share it with your friends. Do you want to share more information about the topic discussed above or do you find anything incorrect? Let us know in the comments. Thank you!

Leave a Comment

Your email address will not be published. Required fields are marked *