3

I'm writing a Rest Service (HTTP Get endpoint), where in the below uri does the following

http://localhost:8080/customers/{customer_id}
  1. fetch the details for the customer_id passed in the uri
  2. if the customer_id is not passed (http://localhost:8080/customers), fetch all the customers details.

Code:

@RequestMapping(method = RequestMethod.GET, value = "customers/{customer_id}")
public List<Customer> getCustomers(
@PathVariable(name = "customer_id", required = false) final String customerId) {
LOGGER.debug("customer_id {} received for getCustomers request", customerId);

}

However, with the above code, for the second scenario control is flowing to getCustomers().

Note: I'm using Java8 and spring-web 4.3.10 version

Highly appreciate any help on this.

tkruse
  • 10,222
  • 7
  • 53
  • 80
technoJ
  • 175
  • 1
  • 1
  • 16

3 Answers3

6

Optional @PathVariable is used only if you want to map both GET /customers/{customer_id} and GET customers into single java method.

You cannot send request which will be sent to GET /customers/{customer_id} if you don't send customer_id.

So in your case it will be:

@RequestMapping(method = RequestMethod.GET, value = {"/customers", "customers/{customer_id}"})
public List<Customer> getCustomers(@PathVariable(name = "customer_id", required = false) final String customerId) {
    LOGGER.debug("customer_id {} received for getCustomers request", customerId);
}

public abstract boolean required

Whether the path variable is required.

Defaults to true, leading to an exception being thrown if the path variable is missing in the incoming request. Switch this to false if you prefer a null or Java 8 java.util.Optional in this case. e.g. on a ModelAttribute method which serves for different requests.

You can use null or Optional from java8

ByeBye
  • 6,650
  • 5
  • 30
  • 63
  • value = {"/customers", "customers/{customer_id}"}) is it ant style. – Lova Chittumuri Nov 30 '17 at 07:26
  • Thanks @ByeBye.. Works like charm. – technoJ Nov 30 '17 at 09:26
  • @ByeBye Just noticed any issue when I gave the request mapping values as array. I had registered a class level request mapping, and the method level request mapping is like the below: @RequestMapping(method = RequestMethod.GET, value = {"/", "/{customer_id}"}). the endpoint is returning a 404 when I call http://localhost:8080/customers (without a trailing slash). Any clue on what's going wrong here. – technoJ Dec 06 '17 at 04:19
  • @ByeBye how could PathVariable can take parameters like required false/true?. Its giving compile time error for me – Rajesh Hatwar Oct 23 '18 at 04:20
  • @RajeshHatwar https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html docs say that parameter is present. – ByeBye Oct 23 '18 at 04:32
1

This may help someone that is trying to use multiple optional path variables.

If you have more than one variable, you can always accept multiple paths. For instance:

@GetMapping(value = {"customers/{customerId}&{startDate}&{endDate}",
"customers/{customerId}&{startDate}&",
"customers/{customerId}&&{endDate}",
"customers/{customerId}&&"
})
public Customer getCustomerUsingFilter(@PathVariable String customerId, @PathVariable Optional<Date> startDate, @PathVariable Optional<Date> endDate)

Then you would call this URL using all the path separators (in this case &)

Like
GET /customers/1&& or
GET /customers/1&&2018-10-31T12:00:00.000+0000 or
GET /customers/1&2018-10-31T12:00:00.000+0000& or
GET /customers/1&2018-10-31T12:00:00.000+0000&2018-10-31T12:00:00.000+0000

Emad Razavi
  • 1,903
  • 2
  • 17
  • 24
Gonçalo
  • 561
  • 5
  • 14
0

You should create two end-point here to handle the individual request :

@GetMapping("/customers")
public List<Customer> getCustomers() {
LOGGER.debug("Fetching all customer");  
}

@GetMapping("/customers/{id}")
public List<Customer> getCustomers(@PathVariable("id") String id) {
LOGGER.debug("Fetching customer by Id {} ",id);  
}

@GetMapping is equivalent to @RequestMapping(method = RequestMethod.GET) and @GetMapping("/customers/{id}") is equivalent to @RequestMapping(method = RequestMethod.GET, value = "customers/{id}")

Better approach would be like this :

@RestController
@RequestMapping("/customers")
public class CustomerController {

    @GetMapping
    public List<Customer> getAllCustomers() {
    LOGGER.debug("Fetching all customer");  
    }

    @GetMapping("/{id}")
    public Customer getCustomerById(@PathVariable("id") String id) {
    LOGGER.debug("Fetching customer by Id {} ",id);  
    }
Mehraj Malik
  • 14,872
  • 15
  • 58
  • 85
  • I initially did this, but both the java methods are intended to do the same operation. I was looking for a single java method which avoids code duplication. Was looking for somwthing like what @ByeBye was suggesting – technoJ Nov 30 '17 at 09:25