Just A Summary

Piers Cawley Practices Punditry

Joined up thinking: why your resources want links 4

Posted by Piers Cawley Fri, 22 Feb 2008 08:26:00 GMT

Remember the good old days? The days before Google? The days before Altavista? The days when a 14k4bps modem was fast? Did I say good old days?

In those days, the web had to be discoverable ‘cos it sure as hell wasn’t searchable. The big, big enabling technology of the web was the humble <a href='http://somewhereelse.com'>Go somewhere else</a>. Placing the links right there in the body of the document turned out to be exactly the right thing to do.

And it continues to be the right thing to do. Consider the two pieces of YAML below the fold.

Here’s something close to what I’ve been generating at work (We generate JSON, but YAML’s easier to write out by hand):


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/...

Here’s that same snippet, recast in the URL free style that’s common in ‘RESTful’ APIs:


id: 99
name: Bill Norrie
creator:
  name: Piers Cawley
  id: pdcawley
duration: 360
image: http://s3.amazonaws.com/...
stream: http://s3.amazonaws.com/...

Which of those would you rather have served up to your API 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’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 principles1.

If you wanted to write a client to make use of resources in the second form, you’d need to know that a tune’s URL is of the form /users/creator.id/tunes/tune_id, that user urls have the form /users/creator.id and so on. You’d curse the API designer who designed that URL scheme. You’d curse again when, having written the Ruby API, you sat down to write the Javascript version (modern sites need their AJAX, right?) and had to teach it all about the URL scheme all over again.

Don’t Repeat Yourself

If there’s one thing worse than violating the DRY principle, it’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 URL generation to the user is multiplied by the number of API client implementations (and, arguably, the number of client that don’t get written ‘cos your API’s a PITA).

It’s worse than that though. You already have the code for mapping between resources and URLs. If you’re using Ruby on Rails, your mapper is bidirectional too2. Generating URLs within your representations should be a snap3. So, what are you waiting for? Start writing Joined Up APIs.

1 For values of ‘the rest’ that are concerned with the how of the API. You’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 <link rel="ServiceDoc" href="/servicedocs/model" /> though.

2 Catch me in the right mood and I can rant for ages about the awfulness of RoR’s routing system, but the bidirectional nature of them trumps almost all my complaints. It’s like Jamie Zawinski’s line that Java doesn’t have free. Everything else about the routing system can suck almost as hard as it likes, but two way routing is a win.

3 Not quite the snap it could be in Rails because rails is of the opinion that URL generation is something the controller does. Which is fine as far as it goes until you find yourself writing Tune#to_json without a controller in sight and you can’t change to_json’s signature because it’s a standard method. And you just want to cry. Model.include ActionController::UrlWriter is wrong, but so tempting… In fact I’ve succumbed, just to get the test to pass. I’m in the process of refactoring by introducing a UrlPolicy singleton that will do all that stuff and at least isolate the bits where my models get to play like controllers.



Just A Summary