A while back we had a Flex client that needed to be able to display search results received from a server. The server was designed RESTfully, returning XML results to the client. The Flex client would display these results nicely to the user, and when the user clicked on a result, their browser would be directed to a HTML page for editing the actual item.
The problem was that, when a client clicked on a result, we were manually constructing the resource URLs in the Flex client from the IDs buried in the search results. The Flex code looked a bit like this:
navigateToURL(new URLRequest('/item/' + result.id +"/edit"),"_self")
Furthermore, we had an impending need to support lots of different types of resources, so our logic for assembling URLs was about to become rather convoluted.
Put the URLs into the search results. It’s blindingly simple (when you think about it, we do it all the time with pure HTML sites), but requires a subtle shift in mindset when you’re writing a fat client.
The solution was prompted by an article on REST Anti-Patterns I had read on InfoQ. – in particular, an anti-pattern called ‘Forgetting hypermedia’:
The first indicator of the “Forgetting hypermedia” anti-pattern is the absence of links in representations. There is often a recipe for constructing URIs on the client side, but the client never follows links because the server simply doesn’t send any.
It goes on to suggest that:
a client should have to know a single URI only; everything else…should be communicated via hypermedia, as links within resource representations.
You wouldn’t want to take this to an extreme, but it’s worth aiming for.
This approach helped simplify our code. We tweaked our server to write the resource URL into our XML, then had the Flex client simply navigate to the URL.
Furthermore, this solution was somewhat polymorphic – a link to any sort of resource could be passed back and the client would always be able to navigate to it.
The only catch was that we had to tweak the server to manually write the paths into the XML. As our server was a Rails app, we found it easiest to just add a ‘.xml.erb’ file to our views directory:
xml.results do @results.each do |result| xml.result do xml.tag! :name, result.name xml.tag! :description, result.description xml.tag! :edit_path, edit_polymorphic_path(result) end end end
Note the use of edit_polymorphic_path to ensure that the path to any sort of resource can be written out.