REST API Best practices: Where to put parameters?


Answers

Late answer but I'll add some additional insight to what has been shared, namely that there are several types of "parameters" to a request, and you should take this into account.

  1. Locators - E.g. resource identifiers such as IDs or action/view
  2. Filters - E.g. parameters that provide a search for, sorting or narrow down the set of results.
  3. State - E.g. session identification, api keys, whatevs.
  4. Content - E.g. data to be stored.

Now let's look at the different places where these parameters could go.

  1. Request headers & cookies
  2. URL query string ("GET" vars)
  3. URL paths
  4. Body query string/multipart ("POST" vars)

Generally you want State to be set in headers or cookies, depending on what type of state information it is. I think we can all agree on this. Use custom http headers (X-My-Header) if you need to.

Similarly, Content only has one place to belong, which is in the request body, either as query strings or as http multipart and/or JSON content. This is consistent with what you receive from the server when it sends you content. So you shouldn't be rude and do it differently.

Locators such as "id=5" or "action=refresh" or "page=2" would make sense to have as a URL path, such as mysite.com/article/5/page=2 where partly you know what each part is supposed to mean (the basics such as article and 5 obviously mean get me the data of type article with id 5) and additional parameters are specified as part of the URI. They can be in the form of page=2, or page/2 if you know that after a certain point in the URI the "folders" are paired key-values.

Filters always go in the query string, because while they are a part of finding the right data, they are only there to return a subset or modification of what the Locators return alone. The search in mysite.com/article/?query=Obama (subset) is a filter, and so is /article/5?order=backwards (modification). Think about what it does, not just what it's called!

If "view" determines output format, then it is a filter (mysite.com/article/5?view=pdf) because it returns a modification of the found resource rather than homing in on which resource we want. If it instead decides which specific part of the article we get to see (mysite.com/article/5/view=summary) then it is a locator.

Remember, narrowing down a set of resources is filtering. Locating something specific within a resource is locating... duh. Subset filtering may return any number of results (even 0). Locating will always find that specific instance of something (if it exists). Modification filtering will return the same data as the locator, except modified (if such a modification is allowed).

Hope this helped give people some eureka moments if they've been lost about where to put stuff!

Question

A REST API can have parameters in at least two ways:

  1. As part of the URL-path (i.e. /api/resource/parametervalue )
  2. As a query argument (i.e. /api/resource?parameter=value )

What is the best practice here? Are there any general guidelines when to use 1 and when to use 2?

Real world example: Twitter uses query parameters for specifying intervals. (http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321)

Would it be considered better design to put these parameters in the URL path?







As a programmer often on the client-end, I prefer the query argument. Also, for me, it separates the URL path from the parameters, adds to clarity, and offers more extensibility. It also allows me to have separate logic between the URL/URI building and the parameter builder.

I do like what manuel aldana said about the other option if there's some sort of tree involved. I can see user-specific parts being treed off like that.




IMO the parameters should be better as query arguments. The url is used to identify the resource, while the added query parameters to specify which part of the resource you want, any state the resource should have, etc.




Here is my opinion.

Query params are used as meta data to a request. They act as filter or modifier to an existing resource call.

Example:

/calendar/2014-08-08/events

should give calendar events for that day.

If you want events for a specific category

/calendar/2014-08-08/events?category=appointments

or if you need events of longer than 30 mins

/calendar/2014-08-08/events?duration=30

A litmus test would be to check if the request can still be served without an query params.




It's a very interesting question.

You can use both of them, there's not any strict rule about this subject, but using URI path variables has some advantages:

  • Cache: Most of the web cache services on the internet don't cache GET request when they contains query parameters. They do that because there are a lot of RPC systems using GET requests to change data in the server (fail!! Get must be a safe method)

But if you use path variables, all of this services can cache your GET requests.

  • Hierarchy: The path variables can represent hierarchy: /City/Street/Place

It gives the user more information about the structure of the data.

But if your data doesn't have any hierarchy relation you can still use Path variables, using comma or semi-colon:

/City/longitude,latitude

As a rule, use comma when the ordering of the parameters matter, use semi-colon when the ordering doesn't matter:

/IconGenerator/red;blue;green

Apart of those reasons, there are some cases when it's very common to use query string variables:

  • When you need the browser to automatically put HTML form variables into the URI
  • When you are dealing with algorithm. For example the google engine use query strings:

http:// www.google.com/search?q=rest

To sum up, there's not any strong reason to use one of this methods but whenever you can, use URI variables.




One "dimension" of this topic has been left out yet it's very important: there are times when the "best practices" have to come into terms with the plaform we are implementing or augmenting with REST capabilities.

Practical example:

Many web applications nowadays implement the MVC (Model, View, Controller) architecture. They assume a certain standard path is provided, even more so when those web applications come with an "Enable SEO URLs" option.

Just to mention a fairly famous web application: an OpenCart e-commerce shop. When the admin enables the "SEO URLs" it expects said URLs to come in a quite standard MVC format like:

http://www.domain.tld/special-offers/list-all?limit=25

Where

  • special-offers is the MVC controller that shall process the URL (showing the special-offers page)

  • list-all is the controller's action or function name to call. (*)

  • limit=25 is an option, stating that 25 items will be shown per page.

(*) list-all is a fictious function name I used for clarity. In reality, OpenCart and most MVC frameworks have a default, implied (and usually omitted in the URL) index function that gets called when the user wants a default action to be performed. So the real world URL would be:

http://www.domain.tld/special-offers?limit=25

With a now fairly standard application or frameworkd structure similar to the above, you'll often get a web server that is optimized for it, that rewrites URLs for it (the true "non SEOed URL" would be: http://www.domain.tld/index.php?route=special-offers/list-all&limit=25).

Therefore you, as developer, are faced into dealing with the existing infrastructure and adapt your "best practices", unless you are the system admin, know exactly how to tweak an Apache / NGinx rewrite configuration (the latter can be nasty!) and so on.

So, your REST API would often be much better following the referring web application's standards, both for consistency with it and ease / speed (and thus budget saving).

To get back to the practical example above, a consistent REST API would be something with URLs like:

http://www.domain.tld/api/special-offers-list?from=15&limit=25

or (non SEO URLs)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

with a mix of "paths formed" arguments and "query formed" arguments.