9

I'm working on a private apis for our backend.
I have collections that have associations.
Each collection can be requested, paginated, you can also ask for the associations and paginate this associations.

We're not sure about which URL design to use ... we're thinking about :

  • /users.json?per_page=10&association=parts,auditions&parts_per_page=5&auditions_per_page=5

  • /users.json?per_page=10&association[]=parts&association[]=auditions&parts_per_page=5&auditions_per_page=10

  • /users.json?per_page=10&association[auditions]=true&association[parts][per_page]=5

What do you think ? which one would you chosse ? why ? is one of this not looking like valid url schemes ?

Thanks !

Mike
  • 5,165
  • 6
  • 35
  • 50

3 Answers3

14

My answer: /users.json. HTTP is optimized for large-grain hypermedia transfer; caching is a big part of this, and none of the URI schemes given above are very cache-friendly.

Squid, for example, is a popular HTTP cache that by default will not cache any URL that has a querystring. In addition, many clients and even servers and intermediaries generate and consume query string parameters in an undefined order; that is, "?a=3&b=5" can be arbitrarily rewritten as "?b=5&a=3". However, for HTTP caching, the order matters, and the two pages will be cached separately even though they have the same content. As you add parameters, this problem increases exponentially.

You should design your resources (and their representations) to take advantage of caching by two opposing but complementary techniques:

  1. Combine fragmented and partial representations into larger, unified representations, and
  2. Separate large, unified representations into smaller representations along cache boundaries (which tend to be transactional boundaries), but related by hyperlinks.

In your case, step 1 implies combining associations and parts into the "users" representation, without any option for the client to configure which ones and how many. That will allow you to aggressively cache the single response representation without overloading your (and their) caches with a combinatorial explosion of responses due to all the querystring options.

Step 2 implies separating /users.json into separate "user" entities, each with an "associations" resource and a "parts" resource. So /users/{id} and /users/{id}/associations and /users/{id}/parts. The "/users" resource then returns an array of hyperlinks to the individual "/users/{id}" resources, and each "/users/{id}` representation contains hyperlinks to its associations and parts (that part is more malleable--it might fit your application better to embed the associations and parts into the user resource directly). That will allow you to aggressively cache the response for each "in demand" resource without having to cache your whole database.

Then your users will scream "but that's 10 times the network traffic!" To which you calmly respond, "no, that's 1/10th the network traffic, because 9 times out of 10 the requested resources are already sitting in your client-side (browser) cache (and when they're not, it's 1/10th the server's computational resources since they're sitting in a server-side cache, and when they're not there either, we avoid stampeding with a smart cache on the server)."

Of course, if the /users resource is something a million new visitors hit every day, then your optimization path might be different. But it doesn't seem so based on your example URI schemes.

fumanchu
  • 14,419
  • 6
  • 31
  • 36
  • Hey fumanchu, thanks for the reply ! I don't get why my urls aren't optimized for cache ? this calls won't be done in a browser but server side (I can easily cache based on url+params). I don't want to separate calls for each associations (that's why my API isn't totally restful), it would mean make multiple calls to get some informations and I don't even with cache ... – Mike Dec 12 '10 at 17:44
  • I added my reply inside my response above (in italics). – fumanchu Dec 13 '10 at 18:14
3

There are a lot of useful posts under the restful-url tag.

Some useful posts:

Do REST API URLs have to look like this?

Best practices on using URIs as parameter value in REST calls.

How to create REST URL's without verbs?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Marcus Leon
  • 55,199
  • 118
  • 297
  • 429
  • Hey Marcus, Thanks for the followup and for tagging it to restful-url, I didn't find any helpful post about using arrays in an API. And I'm not sure this API could be categorized as a restful one, we didn't want to nest everything ... otherwise to get 2 associations from a collections we'd have to make 2 calls and we don't really want that. – Mike Dec 10 '10 at 16:11
1

I would go for the 1st one. I don't like to see the [] notation on the url, IMHO it makes harder for the client to both use and understand. A few changes as suggestions.

1) As association seems to be an array, change for associations (plural, if I am right and it is an array)

2) You can also try to put a default per_page and an optional one, even aggregating, something like per_page_parts_auditions instead of using both per_page_parts and per_page_auditions. I wouldn't do it if your API was designed to be public, since it makes easier to use but harder to understand, but as you posted it is a private one.. should be a good way to avoid replication.

Diego Dias
  • 21,634
  • 6
  • 33
  • 36
  • 1/ agree (it's an array of collections..basically sql relations) 2/ there's already a default per_page (you don't need to define it but you can - there's also {association}_per_page default I just wanted to show you some use cases) and I can't really use a per_page_parts_auditions since I only show you 2 associations but in fact there's a lot more and I have tons of different collections (all with different associations). Our {association}_per_page arguments are generated dynamically. – Mike Dec 10 '10 at 16:25
  • As your {association}_per_page arguments are generated dynamically, can't you make it {associations}_per_page and on your code call the {association}_per_page codes? – Diego Dias Dec 10 '10 at 16:28
  • Sorry I dont get this last question, I'm already asking for {association}_per_page .. – Mike Dec 12 '10 at 19:53