1

I have to write a REST Service method that accepts a list of objects as parameter to calculate something and return a result.

I have so far:

@RequestMapping(value = "generateBill/{id}/{rates}")
public String generateBill(@PathVariable Long id, @PathVariable Rate rates[]) {
   // do things
   return "OK";
}

But I am sure that @PathVariable Rate rates[] is wrong.

I have to write the client part too and I also have no idea how to do it. It is the first time I have to write such a REST Service method.

Edit: Rate looks like this:

public class Rate {
   Long version;
   Double amount;
   Date validFrom;
   Date validUntil;
}
diminuta
  • 1,545
  • 8
  • 32
  • 55

3 Answers3

4

You should put your objects in the body of a POST request instead of using the URL :

@RequestMapping(value = "generateBill/{id}", method = RequestMethod.POST)
public String generateBill(@PathVariable Long id, @RequestBody BillingRequest billingRequest) {
   // do things
}

Also, mapping directly a collection in the payload is not evolvable (you cannot add new "fields" outside the array), it's generally a good practice to wrap your array in a JSON object :

public class BillingRequest {
    List<Rate> rates;
    // Here you could add other fields in the future
}

Your HTTP request to call your service would look like this :

POST / HTTP/1.1
{  
  "rates" : [
     {
       "version" : 1,
       "amount" : 33.3,
       "validFrom" : "2016-01-01",
       "validUntil" : "2017-01-01" 
     },
     {
       "version" : 2,
       "amount" : 10.0,
       "validFrom" : "2016-02-01",
       "validUntil" : "2016-10-01" 
     }
   ] 
}

One last piece of advice about your model :

  • Use java.time.LocalDate (or jodatime) instead of java.util.Date. If you need date+time, use java.time.ZonedDateTime (DateTime if you use jodatime)
  • Use java.math.BigDecimal to represent exact numbers. Floating point numbers like Double can lose precision

EDIT : I would suggest using Instant rather than ZonedDateTime, which is a timestamp with UTC timezone. Unless of course your domain requires different timezones.

Michael Técourt
  • 3,457
  • 1
  • 28
  • 45
  • Thank you very much! I accepted the other solution because he answered first but I think yours should be accepted too but I can't accept two.. – diminuta Aug 17 '16 at 15:03
3

First solution:

@RequestMapping(value = "generateBill/{id}/{rates}", method=RequestMethod.GET)
public String generateBill(@PathVariable Long id, @PathVariable Rate[] rates) {
   // do things
   return "OK";
}

Or second one (more Java style;) ):

@RequestMapping(value = "generateBill/{id}/{rates}", method=RequestMethod.GET)
public String generateBill(@PathVariable Long id, @PathVariable List<Rate> rates) {
   // do things
   return "OK";
}

This one you can call like this:

GET: http://localhost:8080/public/generateBill/1/1,2,3,4 Where 1.2,3,4 replace with your values, it depends od that what exactly is Rate ;)


EDIT

After your update, it looks like that you want to have POST method (you are posting list of rates) and then here is already answered question. receiving json and deserializing as List of object at spring mvc controller

Community
  • 1
  • 1
Hrabosch
  • 1,541
  • 8
  • 12
  • Ok, so I was not very wrong ;P But as of the client? How do I pass the list in the url? – diminuta Aug 15 '16 at 15:24
  • 1
    If there is array, then it will be converted to List ;) – Hrabosch Aug 15 '16 at 15:25
  • 1
    Check my edit. But if you need to pass your object, better for you is using first solution ;) – Hrabosch Aug 15 '16 at 15:28
  • Ok but my problem is that Rate is an object with different properties (see my edit) so I don't know how to add that list to the url. – diminuta Aug 15 '16 at 15:33
  • 1
    So, then it will be POST and you will posting JSON object ;) In this case, you have make POST and set that you are want map your Rate class. Here is already answered question with examples http://stackoverflow.com/questions/23012841/receiving-json-and-deserializing-as-list-of-object-at-spring-mvc-controller – Hrabosch Aug 16 '16 at 09:03
2

Other solution is to use JSON String format as a parameter and parse it afterwards. Something like

[
{
"rates":1, "name":"rate1" }, {
"rates":2, "name":"rate2" }, {
"rates":3, "name":"rate3" } ]

and after that parse the json to your object.

Hristo Staykov
  • 939
  • 7
  • 13