Just A Summary : Tag rest, everything about rest http://www.bofh.org.uk/articles/tag/rest.rss en-us 40 Piers Cawley Practices Punditry Joined up thinking: why your resources want links <p>Remember the good old days? The days before Google? The days before Altavista? The days when a 14k4bps modem was fast? Did I say <em>good</em> old days?</p> <p>In those days, the web had to be discoverable &#8216;cos it sure as hell wasn&#8217;t searchable. The big, big enabling technology of the web was the humble <code>&lt;a href='http://somewhereelse.com'&gt;Go somewhere else&lt;/a&gt;</code>. Placing the links right there in the body of the document turned out to be exactly the right thing to do.</p> <p>And it continues to be the right thing to do. Consider the two pieces of <span class="caps">YAML</span> below the fold.</p> <p>Here&#8217;s something close to what I&#8217;ve been generating at work (We generate <span class="caps">JSON</span>, but <span class="caps">YAML</span>&#8217;s easier to write out by hand):</p> <pre><code> location: http://site/users/pdcawley/tunes/99 name: Bill Norrie creator: name: Piers Cawley location: http://site/users/pdcawley duration: 360 image: http://s3.amazonaws.com/... stream: http://s3.amazonaws.com/... </code></pre> <p>Here&#8217;s that same snippet, recast in the <span class="caps">URL</span> free style that&#8217;s common in &#8216;RESTful&#8217; APIs:</p> <pre><code> id: 99 name: Bill Norrie creator: name: Piers Cawley id: pdcawley duration: 360 image: http://s3.amazonaws.com/... stream: http://s3.amazonaws.com/... </code></pre> <p>Which of those would you rather have served up to your <span class="caps">API</span> client? Obviously, the one with the URLs because then your client has to know so much less. If resources carry links within their body they&#8217;re discoverable, just like anything else on the web. A client only needs to know about a few resource directories and maybe a mechanism for searching, and most of the rest should follow from the RESTful principles<sup><a href="#fn1">1</a></sup>.</p> <p>If you wanted to write a client to make use of resources in the second form, you&#8217;d need to know that a tune&#8217;s <span class="caps">URL</span> is of the form <tt>/users/<var>creator.id</var>/tunes/<var>tune_id</var></tt>, that user urls have the form <tt>/users/<var>creator.id</var></tt> and so on. You&#8217;d curse the <span class="caps">API</span> designer who designed that <span class="caps">URL</span> scheme. You&#8217;d curse again when, having written the Ruby <span class="caps">API</span>, you sat down to write the Javascript version (modern sites need their <span class="caps">AJAX</span>, right?) and had to teach it all about the <span class="caps">URL</span> scheme all over again.</p> <h3>Don&#8217;t Repeat Yourself</h3> <p>If there&#8217;s one thing worse than violating the <span class="caps">DRY</span> principle, it&#8217;s forcing other people to do it. Structuring your APIs representations around IDs rather than URIs is doing just that. The complexity that you dodge by punting <span class="caps">URL</span> generation to the user is multiplied by the number of <span class="caps">API</span> client implementations (and, arguably, the number of client that don&#8217;t get written &#8216;cos your <span class="caps">API</span>&#8217;s a <span class="caps">PITA</span>).</p> <p>It&#8217;s worse than that though. You already <em>have</em> the code for mapping between resources and URLs. If you&#8217;re using Ruby on Rails, your mapper is bidirectional too<sup><a href="#fn2">2</a></sup>. Generating URLs within your representations should be a snap<sup><a href="#fn3">3</a></sup>. So, what are you waiting for? Start writing Joined Up APIs.</p> <p id="fn1"><sup>1</sup> For values of &#8216;the rest&#8217; that are concerned with the how of the <span class="caps">API</span>. You&#8217;re still going to have to document the what and the why. You can get a long way down that road with careful use of <code>&lt;link rel="ServiceDoc" href="/servicedocs/model" /&gt;</code> though.</p> <p id="fn2"><sup>2</sup> Catch me in the right mood and I can rant for ages about the awfulness of RoR&#8217;s routing system, but the bidirectional nature of them trumps almost all my complaints. It&#8217;s like Jamie Zawinski&#8217;s line that <a href="http://www.jwz.org/doc/java.html">Java doesn&#8217;t have <code>free</code></a>. Everything else about the routing system can suck almost as hard as it likes, but two way routing is a win.</p> <p id="fn3"><sup>3</sup> Not quite the snap it could be in Rails because rails is of the opinion that <span class="caps">URL</span> generation is something the controller does. Which is fine as far as it goes until you find yourself writing <code>Tune#to_json</code> without a controller in sight and you can&#8217;t change <code>to_json</code>&#8217;s signature because it&#8217;s a standard method. And you just want to cry. <code>Model.include ActionController::UrlWriter</code> is wrong, but <em>so</em> tempting&#8230; In fact I&#8217;ve succumbed, just to get the test to pass. I&#8217;m in the process of refactoring by introducing a <code>UrlPolicy</code> singleton that will do all that stuff and at least isolate the bits where my models get to play like controllers.</p> Fri, 22 Feb 2008 02:26:00 -0600 urn:uuid:89042495-f6bb-4639-9d93-ab87c0262fd2 pdcawley@bofh.org.uk (Piers Cawley) http://www.bofh.org.uk/articles/2008/02/22/joined-up-thinking-why-your-resources-want-links#comments The Practice of Programming rest http://www.bofh.org.uk/articles/2008/02/22/joined-up-thinking-why-your-resources-want-links