Excellent points. I'd like to add that following links instead of
constructing URIs also enables an evolutionary change of distribution
of resources across multiple servers or domains – something I've found
extremely valuable in scaling a system from deployment to various
(stages of) production environments.
Stefan
On 01.04.2009, at 02:59, Craig McClanahan wrote:
> On Tue, Mar 31, 2009 at 5:01 PM, Solomon Duskis <sduskis@...>
> wrote:
>
> > [snip]
> > Assuming that the practical barriers of entry are removed, what
> practical
> > benefits will we see?
> >
>
> I know exactly where you are coming from with these questions ... I
> felt the same way until recently. I've designed several REST APIs
> over the last couple of years, but up until the most recent one, I
> designed and documented them in the "typical" way, describing the URI
> structure of the application and letting the client figure out what to
> send when. My most recent effort is contributing to the design of the
> REST architecture for the Sun Cloud API[1] to control virtual
> machines and so on. In addition, I'm very focused on writing client
> language bindings for this API in multiple languages (Ruby, Python,
> Java) ... so I get a first hand feel for programming to this API at a
> very low level.
>
> We started from the presumption that the service would publish only
> *one* well-known URI (returning a "cloud" representation containing
> representations for, and/or URI links to representations for, all the
> cloud resources that are accessible to the calling user). Every other
> URI in the entire system (including all those that do state changes)
> are discovered by examining these representations. Even in the early
> days, I can see some significant, practical, short term benefits we
> have gained from taking this approach:
>
> * REDUCED CLIENT CODING ERRORS. Looking back at all the REST client
> side interfaces
> that I, or people I work with, have built, about 90% of the bugs
> have been in the construction
> of the right URIs for the server. Typical mistakes are leaving out
> path segments, getting them
> in the wrong order, or forgetting to URL encode things. All this
> goes away when the server
> hands you exactly the right URI to use for every circumstance.
>
> * REDUCED INVALID STATE TRANSITION CALLS. When the client decides
> which URI to call and
> when, they run the risk of attempting to request state transitions
> that are not valid for the current
> state of the server side resource. An example from my problem
> domain ... it's not allowed to
> "start" a virtual machine (VM) until you have "deployed" it. The
> server knows about URIs to
> initiate each of the state changes (via a POST), but the
> representation of the VM lists only the
> URIs for state transitions that are valid from the current state.
> This makes it extremely easy
> for the client to understand that trying to start a VM that hasn't
> been deployed yet is not legal,
> because there will be no corresponding URI in the VM representation.
>
> * FINE GRAINED EVOLUTION WITHOUT (NECESSARILY) BREAKING OLD CLIENTS.
> At any given time, the client of any REST API is going to be
> programmed with *some* assumptions
> about what the system can do. But, if you document a restriction to
> "pay attention to only those
> aspects of the representation that you know about", plus a server
> side discipline to add things later
> that don't disrupt previous behavior, you can evolve APIs fairly
> quickly without breaking all clients,
> or having to support multiple versions of the API simultaneously on
> your server. You don't have to
> wait years for serendipity benefits :-). Especially compared to
> something like SOAP where the
> syntax of your representations is versioned (in the WSDL), so you
> have to mess with the clients
> on every single change.
>
> Having drunk the HATEOAS koolaid now, I would have a really hard time
> going back :-).
>
> Craig McClanahan
>
> [1] http://kenai.com/projects/suncloudapis/pages/Home
>
> <!-- #ygrp-mkp{ border: 1px solid #d8d8d8; font-family: Arial;
> margin: 14px 0px; padding: 0px 14px; } #ygrp-mkp hr{ border: 1px
> solid #d8d8d8; } #ygrp-mkp #hd{ color: #628c2a; font-size: 85%; font-
> weight: bold; line-height: 122%; margin: 10px 0px; } #ygrp-mkp
> #ads{ margin-bottom: 10px; } #ygrp-mkp .ad{ padding: 0 0; } #ygrp-
> mkp .ad a{ color: #0000ff; text-decoration: none; } --> <!-- #ygrp-
> sponsor #ygrp-lc{ font-family: Arial; } #ygrp-sponsor #ygrp-lc
> #hd{ margin: 10px 0px; font-weight: bold; font-size: 78%; line-
> height: 122%; } #ygrp-sponsor #ygrp-lc .ad{ margin-bottom: 10px;
> padding: 0 0; } --> <!-- #ygrp-mlmsg {font-size:13px; font-family:
> arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}
> #ygrp-mlmsg table {font-size:inherit;font:100%;} #ygrp-mlmsg select,
> input, textarea {font:99% arial,helvetica,clean,sans-serif;} #ygrp-
> mlmsg pre, code {font:115% monospace;*font-size:100%;} #ygrp-mlmsg *
> {line-height:1.22em;} #ygrp-text{ font-family: Georgia; } #ygrp-
> text p{ margin: 0 0 1em 0; } dd.last p a { font-family: Verdana;
> font-weight: bold; } #ygrp-vitnav{ padding-top: 10px; font-family:
> Verdana; font-size: 77%; margin: 0; } #ygrp-vitnav a{ padding: 0
> 1px; } #ygrp-mlmsg #logo{ padding-bottom: 10px; } #ygrp-reco
> { margin-bottom: 20px; padding: 0px; } #ygrp-reco #reco-head { font-
> weight: bold; color: #ff7900; } #reco-category{ font-size: 77%; }
> #reco-desc{ font-size: 77%; } #ygrp-vital a{ text-decoration:
> none; } #ygrp-vital a:hover{ text-decoration: underline; } #ygrp-
> sponsor #ov ul{ padding: 0 0 0 8px; margin: 0; } #ygrp-sponsor #ov
> li{ list-style-type: square; padding: 6px 0; font-size: 77%; } #ygrp-
> sponsor #ov li a{ text-decoration: none; font-size: 130%; } #ygrp-
> sponsor #nc{ background-color: #eee; margin-bottom: 20px;
> padding: 0 8px; } #ygrp-sponsor .ad{ padding: 8px 0; } #ygrp-
> sponsor .ad #hd1{ font-family: Arial; font-weight: bold; color:
> #628c2a; font-size: 100%; line-height: 122%; } #ygrp-sponsor .ad
> a{ text-decoration: none; } #ygrp-sponsor .ad a:hover{ text-
> decoration: underline; } #ygrp-sponsor .ad p{ margin: 0; } o{font-
> size: 0; } .MsoNormal{ margin: 0 0 0 0; } #ygrp-text tt{ font-size:
> 120%; } blockquote{margin: 0 0 0 4px;} .replbq{margin:4} dd.last p
> span { margin-right: 10px; font-family: Verdana; font-weight:
> bold; } dd.last p span.yshortcuts { margin-right: 0; } div.photo-
> title a, div.photo-title a:active, div.photo-title a:hover,
> div.photo-title a:visited { text-decoration: none; } div.file-title
> a, div.file-title a:active, div.file-title a:hover, div.file-title
> a:visited { text-decoration: none; } #ygrp-msg p { clear: both;
> padding: 15px 0 3px 0; overflow: hidden; } #ygrp-msg p span { color:
> #1E66AE; font-weight: bold; } div#ygrp-mlmsg #ygrp-msg p a
> span.yshortcuts { font-family: Verdana; font-size: 10px; font-
> weight: normal; } #ygrp-msg p a { font-family: Verdana; font-size:
> 10px; } #ygrp-mlmsg a { color: #1E66AE; } div.attach-table div div a
> { text-decoration: none; } div.attach-table { width: 400px; } -->