40
RESTful Service Best Practices
GET http://www.example.com/customers/33245
There are good arguments on both sides, but the commonly-accepted practice is to always use plurals
in node names to keep your API URIs consistent across all HTTP methods. The reasoning is based on
the concept that customers are a collection within the service suite and the ID (e.g. 33245) refers to one
of those customers in the collection.
Using this rule, an example multi-node URI using pluralization would look like (emphasis added):
GET http://www.example.com/customers/33245/orders/8769/lineitems/1
with 'customers', 'orders', and 'lineitems' URI nodes all being their plural forms.
This implies that you only really need two base URLs for each root resource. One for creation of the
resource within a collection and the second for reading, updating and deleting the resource by its
identifier. For example the creation case, using customers as the example, is handled by the following
URL:
POST http://www.example.com/customers
And the read, update and delete cases are handled by the following:
GET|PUT|DELETE http://www.example.com/customers/{id}
As mentioned earlier, there may be multiple URIs for a given resource, but as a minimum full CRUD
capabilities are aptly handled with two simple URIs.
You ask if there is a case where pluralization doesn't make sense. Well, yes, in fact there is. When
there isn't a collection concept in play. In other words, it's acceptable to use a singularized resource
name when there can only be one of the resource—it's a singleton resource. For example, if there was
a single, overarching configuration resource, you might use a singularized noun to represent that:
GET|PUT|DELETE http://www.example.com/configuration
Note the lack of a configuration ID and usage of POST verb. And say that there was only one
configuration per customer, then the URL might be:
GET|PUT|DELETE http://www.example.com/customers/12345/configuration
Again, no ID for the configuration and no POST verb usage. Although, I'm sure that in both of these
cases POST usage might be argued to be valid. Well... OK.
Returning Representations
As mentioned earlier, it is desirable for a service to support multiple representations of resources,
including JSON and XML, as well as wrapped JSON and XML. As the default representation, the
recommendation is JSON, but services should allow clients to specify alternative representations.
For a client to request a representation format, there is a question around whether to use the Accept
header a file-extension-style format specifier, query-string parameter, etc. Optimally, services would
support all of those methods. However, industry is currently converging on using a format specifier,
which looks more like a file extension. Therefore, the recommendation is that, at a minimum, services
support the use of file extensions such as '.json', '.xml' and wrapped options, '.wjson' and '.wxml'.
05/29/12
www.RestApiTutorial.com
Page 17 of 34
45
RESTful Service Best Practices
Using this technique, the representation format is specified in the URI, enhancing visibility. For
example, GET http://www.example.com/customers.xml would return the list of customer representations
in XML format. Likewise, GET http://www.example.com/customers.json would return a JSON
representation. This makes the services simple to use from even the most basic client (such as 'curl')
and is recommended.
Also, services should return the default representation format (presumably JSON) when a format
specifier is not included on the url. For example:
GET http://www.example.com/customers/12345
GET http://www.example.com/customers/12345.json
Both of the above return the 12345 customer resource in a JSON representation, which is the default
format for this service.
GET http://www.example.com/customers/12345.xml
Returns the 12345 customer resource in an XML representation, if supported. If an XML representation
of this resource is not supported by this service, an HTTP 404 error should be returned.
Use of the HTTP Accept header is considered by many to be a more elegant approach, and is in
keeping with the meaning and intent of the HTTP specification with regards to how clients notify
HTTP servers of which content types they support. However, to support both wrapped and unwrapped
responses from your services, in order to utilize the Accept header, you must implement your own
custom types—since there are no standard types for these formats. This increases the complexity of
both clients and services greatly. See Section 14.1 of RFC 2616
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
) for details on the Accept header.
Supporting file-extension-style format specifiers is simple, straight-forward, gets the job done in the
fewest number of characters, and easily supports scripting—without having to leverage HTTP headers.
In general, when we talk about REST services, XML is largely irrelevant. Barely anyone uses XML
with REST although supporting XML is recommended. XML standards and conventions are really not
in play. In particular, namespaces are not, nor should they be use in a RESTful service context. It just
muddies the waters and makes things more complicated. So the XML that is returned is more JSON
like—simple and easy to read, without the schema and namespace constraints—non-standard in other
words, but parse-able.
Resource Discoverability Through Links (HATEOAS cont'd)
One of the guiding principals of REST (via the Uniform Interface constraint) is that application state is
communicated via hypertext. This is often referred to as Hypertext As The Engine of Application State
(HATEOAS) as mentioned above in the What is Rest? Section.
According to Roy Fielding's blog (at http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-
driven
), the most important part of a REST interface is its usage of hypertext. Further, he states that an
API should be usable and understandable given an initial URI without prior knowledge or out-of-band
information. That is, an API should be navigable via its links to various components of the data.
Returning only data representations is discouraged.
This practice is not often followed by current industry leaders in services, reflecting that HATEOAS
05/29/12
www.RestApiTutorial.com
Page 18 of 34
42
RESTful Service Best Practices
usage is higher on the maturity model. Looking around at many services, convention is to return more
data and less (or no) links. This is contrary to Fielding's REST constraints. Fielding says, “Every
addressable unit of information carries an address... Query results are represented by a list of links with
summary information, not by arrays of object representations.”
On the other hand, simply returning collections of links can be a major cause of network chattiness. In
the real world, depending on requirements or use cases, chattiness of the API interface is managed by
balancing how much “summary” data is included along with the relational hypertext links in service
responses.
Also, full use of HATEOAS can increase implementation complexity and impose a significant burden
on service clients, decreasing developer productivity on both client and server ends of the equation.
Consequently, it is imperative to balance hyperlinking service implementations with available
development resources.
A minimal set of hyperlinking practices provides major gains in service usability, navigability and
understandability while minimizing development impact and reducing the coupling between client and
server. These minimal recommendations are resources created via POST and for collections returned
from GET requests, with additional recommendations for pagination cases, which are described below.
Minimal Linking Recommendations
In create use cases, the URI (link) for the newly-created resource should be returned in the Location
response header and the response body be empty—or contain only the ID of the newly-created
resource.
For collections of representations being returned from a service, each representation should minimally
carry a 'self' link property in its own links collection. Other links may be present in the returned as a
separate links collection to facilitate pagination, with 'first', 'previous', 'next', 'last' links where
applicable.
See the examples in the Link Format section below for more information.
Link Format
Regarding overall link format standards it is recommended to adhere to some semblance of the Atom,
AtomPub, or Xlink style. JSON-LD is getting some traction too, but is not widely adopted yet (if it
ever will be). Most widespread in the industry is usage of the Atom link style with a “rel” element and
an “href” element that contains the full URI for the resource without any authentication or query-string
parameters. The “rel” element, can contain the standard values "alternate", "related", "self",
"enclosure", and "via", plus “first”, “last”, “previous”, “next” for pagination links. Use them where
they make sense and add your own when needed.
Some of the XML Atom format concepts are somewhat irrelevant for links being represented in JSON.
For instance, the METHOD property is not needed for a RESTful resource since the URIs are the same
for a given resource, with all of the HTTP methods being supported (for CRUD behavior)--so listing
them individually is overkill.
Let's make all this talk a little more concrete with some examples. Here's what the response would
05/29/12
www.RestApiTutorial.com
Page 19 of 34
41
RESTful Service Best Practices
look like after creating a new resource with a call to:
POST http://api.example.com/users
And here's an example set of response headers with the Location header set containing the new
resource URI:
HTTP/1.1 200 OK
Status: 200
Connection: close
Content-Type: application/json; charset=utf-8
Location: http://api.example.com/users/12346
The body is either empty, or contains a wrapped response (see Wrapped Responses below).
Here is an example JSON response to a GET request that returns a collection of representations without
pagination involved:
{“data”:[{“user_id”:”42”, “name”:”Bob”, “links”:[{“rel”:”self”,
“href”:”http://api.example.com/users/42”}]}, {“user_id”:”22”, “name”:”Frank”, “links”:
[{“rel”:”self”, “href”:”http://api.example.com/users/22”}]}, {“user_id”:”125”, “name”: “Sally”,
“links”:[{“rel”:”self”, “href”:”http://api.example.com/users/125”}]}]}
Note the links array containing a single reference to “self” for each item in the collection. This array
could potentially contain other relationships, such as children, parent, etc.
The final example is a JSON response to a GET request that returns a collection where pagination is
involved (we're using three items per page) and we're on the third page of the collection:
{“data”:[{“user_id”:”42”, “name”:”Bob”, “links”:[{“rel”:”self”,
“href”:”http://api.example.com/users/42”}]}, {“user_id”:”22”, “name”:”Frank”, “links”:
[{“rel”:”self”, “href”:”http://api.example.com/users/22”}]}, {“user_id”:”125”, “name”: “Sally”,
“links”:[{“rel”:”self”, “href”:”http://api.example.com/users/125”}]}], “links”:[{“rel”:“first”,
“href”:”http://api.example.com/users?offset=0&limit=3”}, {“rel”:“last”,
“href”:”http://api.example.com/users?offset=55&limit=3”}, {“rel”:“previous”,
“href”:”http://api.example.com/users?offset=3&limit=3”}, {“rel”:”next”,
“href”:”http://api.example.com/users?offset=9&limit=3”}]}
In this example, the links collection in the response is populated for pagination purposes along with the
link to “self” in each of the items in the collection. There could be additional links here related to the
collection but not related to pagination. The simple summary is, there are two places to include links in
a collection. For each item in the collection (those in the data object, which is the collection of
representations requested), include a links collection that, minimally, would contain a “self” reference.
Then, in a separate object, links, include links that apply to the entire collection as applicable, such as
pagination-related links.
For the create use case—create via POST, include a Location header with a link to the newly-created
object.
05/29/12
www.RestApiTutorial.com
Page 20 of 34
Documents you may be interested
Documents you may be interested