13

I am designing a RESTful API.

One service should offer query functionality for multiple key-value pairs. For example, the client can query with one HTTP GET request for different products and the associated quantity.

The client wants to query product 1 with the amount 44 AND product 2 with the amount 55. I actually don't want my URI to look like this:

/produkt?productId1=1&productquantity1=44&productId2=2&productquantity2=55

because I don't know how many products are queried.

Or like this:

/produkt?product=1,44&product=2,55

because how can the client know that before the comma there is the productId and after the comma the quantity.

Does anyone have other solutions? Or is it not RESTful to offer the possibility to query multiple products with one request? Is it better to offer the possibility to query just one product with the associated quantity and if the client wants to query more products, they should send more requests?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
joshi737
  • 869
  • 3
  • 12
  • 26
  • what would be wrong with putting the query information into a http-post? – schippi Dec 09 '12 at 15:38
  • 2
    @schippi Nothing, except that that wouldn't be RESTful :) – Sergey Kalinichenko Dec 09 '12 at 15:39
  • RESTful web services do not have to be exclusively based on GET. You could easily have a RESTful service that requires the transmission of more data than can be included in a GET request. It is reasonable to use any HTTP method. See: http://en.wikipedia.org/wiki/Representational_state_transfer#Vocabulary_re-use_vs._its_arbitrary_extension:_HTTP_and_SOAP – Michael Dec 09 '12 at 15:47
  • 2
    @Michael If you were to use a POST request to "get" data, that would NOT be RESTful. The point is using the HTTP verbs to correspond to the action. i.e. GET for fetching data, POST for creating data, PUT for updating data, and DELETE for deleting data, etc. – Alex White Nov 23 '15 at 18:25

3 Answers3

7

Here is one idea to pass a parameter:

/products?productDetail=[{"key":"key0","value":"key1"},{"key":"key2","value":"key2"},{"key":"key3","value":"key3"}]

where

[{"key":"key0","value":"key1"},{"key":"key2","value":"key2"},{"key":"key3","value":"key3"}]

is a JSON representation of the List<kv> class

class kv {
    String key;
    String value;


    public kv(String key, String value) {
        super();
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

so you can easily convert query parameter productDetail in to List<kv> using

new Gson().fromJson(productDetail,kv.class);

than you can easily iterate all elements.

Another suggestion is, if you don't know how many products are queried then use a POST request for this.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Yogesh Prajapati
  • 4,770
  • 2
  • 36
  • 77
  • Like this idea, I would consider putting (query should be idempotent) the JSON, instead of using the GET query. – Stefan Dec 09 '12 at 16:04
2

I would expand upon your second suggestion a little by adding explicit names for the parts of your product, and using semicolons in place of commas to separate product attributes, since the order does not matter*.

/products?id=1;qty=44&qty=55;id=2

Note how id and qty are switched around for the second product, because the order of attributes does not matter.


* There is a convention to use commas when the order is important, and semicolons when the order is not important.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • How can I inject those params into my REST Service? I know, I have to use the @QueryParam-Annotation, but how should I use this? – joshi737 Dec 09 '12 at 17:05
  • Using semicolons like this would be very unexpected. It also goes against the W3C recommendation (see: https://stackoverflow.com/a/40768572/1361980). – kalmas Sep 26 '20 at 13:23
0

The most idiomatic HTTP GET way I can think to do it:

/produkt?productId=1&productquantity=44&productId=2&productquantity=55

I ran into a similar situation recently where Clients needed to be able to search by "Product Attributes" which are defined arbitrarily for each Product. Clients also needed to be able to create these links easily and pass them around via email, etc. I didn't want to create a custom query string because I didn't want to create a custom parser and it adds an extra step where the Client could make a mistake. And I didn't want to pass json as it relied on the Client to generate that JSON in some cases.

While the HTTP Spec doesn't take a hard stance on multiple values per parameter, every example I can find indicates that order is preserved. Java example:

String[] productIds = this.request.getParameterValues("productId");
String[] productQuantities = this.request.getParameterValues("productquantity");

productIds[0]; // 1
productQuantities[0]; // 44
productIds[1]; // 2
productQuantities[1]; // 55

I'll leave error and index range checking as an exercise for the reader.

Josh Johnson
  • 10,729
  • 12
  • 60
  • 83