on the web, links use URIs as identifiers, and while in theory each REST service should provide a single URI as an entry point, in practice, the exact concept of an entry point
is hard to nail down. that's because one of the nice things about hypermedia is that for clients, boundaries between services
disappear, and they can simply traverse a web of interlinked resources, blissfully ignoring deployment details.
this is a powerful architectural principle, and even more so in a world where deployment details should be opaque and could change at any time, without risking disrupting clients. cloud and SaaS proponents often focus on how these approaches decouple service provision and service consumption, and REST and in particular its hypermedia constraint can play an important role in this picture.
what this means is the following: URIs as entry points
are a powerful concept, and services should be designed so that ideally, all of their URIs can be entry points. this means that any URI should allow clients to bootstrap themselves, with the first step being understanding what that URI actually identifies, and what interactions are possible.
as a client traversing hypermedia, the process is that i have some state that contains links, i choose the next interaction based on link types (often using link relations or custom link structures), which represent the why (why should i follow this link?
) of a link. the context where i find this link also gives me a clue on how to use the link: the context's media type should tell me not just where links are, but also what to do with them. however, the media type might simply not do this, either because it has not been designed this way, or because the authors chose to not constrain links in any way. if the media type does provide interaction information, however, it may do so at design time, at runtime, or both.
one example for design time interaction information is AtomPub, where the media type defines that when a member URI is found, it may support GET
, PUT
, and/or DELETE
. one example for runtime interaction information is HTML, where the method attribute provides a runtime hint for how to submit form values to the action URI. in both cases, a client finding the URI can use source context information (design time or runtime context) to understand the affordances of the target URI.
if such a URI is shared or bookmarked, this context may get lost, however, and thus a client would be left with the URI alone, wondering how to interact. but HTTP provides a bootstrapping mechanism: OPTIONS
. however, this does not provide the full picture. for example, an OPTIONS
request on an AtomPub member URI may result in the following response header:
Allow: GET, PUT, DELETE
but that would not tell the client what is acceptable as content in PUT
requests. also, different methods might expect different media types. PATCH
, for example, comes with its own Accept-Patch
header field that allows an OPTIONS
response to specify the accepted PATCH
document formats. for POST
, HTTP does not have a built-in header field, but Accept-Post
has been proposed recently. however, we're still left with a patchwork of hard-to-represent information, scattered across HTTP headers, or not being representable in HTTP headers at all.
luckily, OPTIONS
allows to respond with content, which could contain a much richer and better structured representation of the interaction affordances of a resource.
designing OPTIONS
responses thus can be a very good place to make a REST service truly self-describing. it should provide all of the information that might help a client to start interacting, including rather advanced information such as URI Templates. another good design goal is to make that representation reusable, so that it can be provided as a representation on the URI itself, but also can be embedded in a link (i.e., on the source side of a link). and finally, why not also make this available as documentation of the media type, since we're designing a representation for interaction information?
in such a design, there are four sources where clients might get interaction information:
- media types containing links may define constraints that allow clients to follow links in a certain way (AtomPub).
- media types might provide runtime information allowing clients to decide at runtime how to follow links in a certain way (HTML form submission).
- link target URIs might expose interaction information as a response to
OPTIONS
requests. - link target URIs behave in a way so that clients simply interacting with them can learn from them (
Accept-Post
in a response to aGET
request).
step 4 is taken care of by what can be represented in HTTP itself. however, for steps 1-3, it would make sense to use the same model of how link interaction information is represented. because this can be important bootstrapping information for clients, Home Documents for HTTP APIs include link interaction information. the current version has this as an integral part of the home document format itself.
however, thinking through the above scenarios, it seems that it better should be designed standalone, and made reusable. then it can be reused in the home document format, in other media types as well, and it also can be used standalone as a response format for OPTIONS
. currently, two such proposals are under development:
- mark nottingham's link hints take the home document model, and propose it as a separate model for a future version of the home document draft.
- my own link descriptions are similar, but a bit more ambitious, most importantly by adding support for URI templates, and registering a media type so that it can be used standalone. here's a simple "edit" link description example and there's even some primitive XML-to-HTML XSLT.
both drafts are -00 and need some work, and since there is a lot of overlap, they should be combined/merged at some point in time. for the link description work, the next version will make the model more hierarchical, so that it is easier to have "conditional hints" based on HTTP methods (and maybe even media types), representing constraints such as PUT
requests accept image/png
up to a maximum size of 50mb.
finally, the grand plan for all of this is to reuse it in a documentation framework called Sedola, which supports structured access to documentation of media types and other REST concepts (see the example for AtomPub which then is used to generate compiled documentation such as this list of link relations from a variety of specifications), but should also support capturing link information (and some other things that i'll write about another day).
driving link hints/descriptions forward can improve the runtime experience for REST services (both as source-side embedded information, and as target-side self-describing information). it also plays an important role in improving (access to) service documentation. it seems like the idea has popped up in a variety of places already, but i've never seen it pulled together across steps 1-3 presented above. is it a worthwhile effort to design such a reusable link information model? time will tell...
While I also was in favor of OPTIONS, mnot points out some counterarguments: http://www.mnot.net/blog/2012/10/29/NO_OPTIONS
How about we use just HTTP linking to a description and then GET?
Posted by: Ruben Verborgh | Wednesday, October 30, 2013 at 02:17
@RubenVerborgh, thanks for the comment. exposing the link hint/description via OPTIONS is just one way of doing it, and may not be so working so great in practice, given mark's reservations about cacheability. but if you simply replaced the OPTIONS approach with (and the current link descriptions draft actually does propose such a link relation http://tools.ietf.org/html/draft-wilde-link-desc-00#section-6.2), i think you end up with pretty much the same line of argument, but without the potential drawbacks of using OPTIONS. you could also decide to embed the link description in the representation you GET, but that might be very noisy and not what you want to do in practice. do you see anything wrong with that picture?
Posted by: dret | Wednesday, October 30, 2013 at 11:40
No, that's indeed a solution. Just a pity that it was decided to make OPTIONS non-cacheable—now we have the choice between an extra HTTP request or a noisy representation. Luckily, the automated discovery mechanism remains intact.
Posted by: Ruben Verborgh | Wednesday, October 30, 2013 at 15:12