A RESTful API needs to have one and exactly one entry point. The URL of the entry point needs to be communicated to API clients so that they can find the API.
Technically speaking, the entry point can be seen as a singleton resource that exists outside any collection. It is common for the entry point to contain some or all of the following information:
- Information on API version, supported features, etc.
- A list of top-level collections.
- A list of singleton resources.
- Any other information that the API designer deemed useful, for example a small summary of operating status, statistics, etc.
Each collection and resource in the API has its own URL. URLs should never be constructed by an API client. Instead, the client should only follow links that are generated by the API itself.
The recommended convention for URLs is to use alternate collection / resource path segments, relative to the API entry point. This is best described by example. The table below uses the ”:name” URL variable style from Rail’s “Routes” implementation.
|/api||The API entry point|
|/api/:coll||A top-level collection named “coll”|
|/api/:coll/:id||The resource “id” inside collection “coll”|
|/api/:coll/:id/:subcoll||Sub-collection “subcoll” under resource “id”|
|/api/:coll/:id/:subcoll/:subid||The resource “subid” inside “subcoll”|
Even though sub-collections may be arbitrarily nested, in my experience, you want to keep the depth limited to 2, if possible. Longer URLs are more difficult to work with when using simple command-line tools like curl.
Relative vs Absolute¶
It is strongly recommended that the URLs generated by the API should be absolute URLs.
The reason is mostly for ease of use by the client, so that it never has to find out the correct base URI for a resource, which is needed to interpret a relative URL. The URL RFC specifies the algorithm for determining a base URL, which is rather complex. One of the options for finding the base URL is to use the URL of the resource that was requested. Since a resource may appear under multiple URLs (for example, as part of a collection, or stand-alone), it would be a significant overhead to a client to remember where he retrieved a representation from. By using absolute URLs, this problem doesn’t present itself.
A draft standard for URL templates exists. URL templates can be useful in link attributes where the target URL takes query arguments. It is recommended though to make only conservative use of these. So far the only good use case I have come across is when searching in a collection. In that case, it seems fair that the search criteria can be specified as GET style query arguments appended to the collection URL.
I would recommend to only use the “literal expansion” part of the URL templates spec, because the “expression expansion” part adds too much complexity to a client in my view, for very little benefit.
Sometimes you need to work on a variant of a resource. In our RHEV-M API for example, some attributes on a virtual machine can be updated while a virtual machine is running. This amounts to a hot plug/unplug of the resource, which is a different operation altogether from changing the saved representation. A nice way to implement this is using ”;variant” identifier in a URL. For example:
|/api/:coll/:id;saved||Identifies the saved variant of a resource.|
|/api/:coll/:id;current||Identifies the current variant of a resource.|
The use of the semicolon to provide options that are specific to a path segment is explicitly alowed in RFC3986 The advantage over using a ”?variant” query argument is that this format is specific to a path segment only, and would allow you to e.g. work on the saved variant of a sub-resource in a sub-collection of the current variant of another resource.