====
URLs
====
Entry Point
===========
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.
URL Structure
=============
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.
============================== =============================================
URL Description
============================== =============================================
/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.
URL Templates
=============
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.
Variants
========
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:
====================== =============================================
URL Description
====================== =============================================
/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.