GETting RESTful collections - may I filter?

At work at Ibuildings recently, I've been teaching some classes on web services, and its a topic that I've spoken about once or twice at conferences. But something has always bothered me, so I find myself in the unusual position of blogging a question.

RESTful collections

So, when you are retrieving information from a RESTful service. You have two options: retrieve a specific resource, whose URL you know; or retrieve a collection, which may contain a list of resources. I've also seen some nice ways of filtering collections, by creating kind of "sub collections" or "views", similar to what twitter does with the URL of lists, for example http://twitter.com/dpcon/speakers10 which is like a filtered list of twitter users.

What if I want to search and sort?

Is it RESTful to add GET parameters to a collection in order to add functionality such as filtering, sorting, or pagination? What I have in mind is a URL that looks something like this:

  • http://example.com/users?orderby=firstname&start=0
  • http://example.com/users?start=0&limit=25
  • http://example.com/users?active=1&orderby=join_date&limit=12

This is what I would do with a search results page in a web application, and I use the same approach to web services which works really well and I recommend it to everyone! But is it RESTful?

I am also wondering where OpenSearch would fit into the answer for all this, I only noticed it recently but the more I look at it the more I think it could be an interesting addition!

Thoughts, links for me to RTFM, and all other additions are welcome in the comments box :)

19 thoughts on “GETting RESTful collections - may I filter?

  1. First!!! xD
    Humm yeah reduce @ URl? Wouldnt make sense to send them via Post / Put so... Thats how CouchDB does it and im fine with it ;)

  2. REST is an architectural style, not a protocol; and there's no single defined standard. I interpret the term "RESTful" as merely meaning "conforming to REST architecture"; the whole World Wide Web is a REST-based system, so I reckon that anything you'd commonly see on the Web is "RESTful"

  3. > Is it RESTful to add GET parameters
    > to a collection in order to add
    > functionality such as filtering,
    > sorting, or pagination?

    They're not actually called GET parameters, they're called query parameters. PHP actually has it wrong on that subject ;) Anyway, yes, I'd imagine that is the best way to do it. In REST-ful applications, the URI must represent a resource (an a collection of resources is, in and on itself, a resource). The filtering solution twitter (and others) use is elegant, but if you want it to sort in a certain way, there is no other way than passing it in the query string, without violating the "A URI is a resource" mantra. I don't think it's a bad thing to do so.

  4. > Is it RESTful to add GET parameters to
    > a collection in order to add
    > functionality such as filtering,
    > sorting, or pagination?

    Yes, I think so, because the query string is also just a part of the uri. So the collection -- as a resource -- stays identifyable. One entity resource may also get identifyable by more than one uri, which means, that the way twitter solved this, can be considered as a reference to the "real uri" with query string.

  5. I think query parameters are okay as well.

    Search and filtered sets kinda push the boundaries of what it is useful to make RESTful. (For search, what's the "resource"? What would it mean to DELETE or POST to the resource?)

    There isn't sensible RESTful version of every API; if what you want to do is not really based around "resources" (in the HTTP sense), then there's no point making it RESTful. I don't think it's possible to make a reasonable RESTful interface to a chess server, for example. (The only way to do it is to tunnel a non-RESTful API.)

        • There is state. If there was no state there would be no reason to have resource references. Each resource has a state, so in a restful chess server would just have each piece as a resource. The state of the pieces would then be persisted with each move. And a move would actually be very simply a PUT on the piece with it's new location data, or if you would rather a POST to the piece, either would work. REST is a different way of think.

          • "a restful chess server would just have each piece as a resource"

            I don't think this really makes sense. It's tempting to treat pieces as resources since some of the operations you want to perform on pieces seem to match the operations on typical RESTful resources (like DELETE), but some many operations that you'd want to support in a chess service are very difficult to manage in a RESTful way. How do you find out the moves in the game so far? How do you figure out if a move is valid or not? How do you take a move back? How do you get a hint? I don't think it's possible to implement these things in a genuinely RESTful way--you'd end up essentially tunnelling a non-RESTful API over REST--and it would be a pain to use, especially compared to a system based around algebraic chess notation, which would not treat pieces as "resources."

            I don't think a RESTful interface makes sense for most games, even if the games themselves have the concept of resources. e.g. Risk, Scrabble, Monopoly. How would you transfer one Monopoly resource from one player to another? Custom HTTP verbs plus headers?

  6. Thanks so much for all your thoughts so far - you've given me lots of ideas and I feel better about the fact that I'm adding these filtering parameters to my own services now :)

  7. Sorry to "revive" the topic but : in the end, what did you do ?

    I think there are 2 schools :
    * you add query parameters to the get
    * you first post to create a query (/users/queries) then you get the query (/users/queries/1)

    I know that the trac project (and others) use the first approach

    The advantage of the second approach are :
    * you can have a very long query (whereas with a get you are limited to 8092 bytes)
    * you can easily share the url
    * you can easily consider to retrieve the query as xls or xml or json (/users/queries/1.json)
    * you can create syndicate feeds very easily (this is also possible with the get approach but it is less natural)

    What do you think ?

    • I think that there is third school:
      * use [custom] http headers

      The second solution approach you proposed is great for queries, like collection filtering, but it makes no sense to me send POST request just for new range of items.

      My proposal:
      use [custom] http headers for paggination/range, sorting
      use POST request for quering/filtering

      Is it Zen of RESTful collection processing or not? ;)

  8. chris: I added GET parameters to my search query :) Thanks for adding a comment, I really must fix the markup in these comment boxes one day ... its on my todo list but it has been for a couple of years!

  9. Thank you very much for this discussion. I've been attempting to write a RESTful search controller in Spring and have had a difficult time wrapping my head around what to do.

    I think I'm going to go with adding query parameters to the get.

    So that if I have a collection of shirts, i would get the first shirt with
    /shirt/1

    but i would get all the shirts in the collection with
    /shirt

    If i want to search for a grouping of shirts that are blue, the i'll do something like:
    /shirt?q=color:blue&sort=length desc&start=0&rows=100

    The underlying spring impl gets tricky because the search will be hitting against a solr instance while the retrieval of a single object goes against a datastore.

    oh well, cheers!

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>