21 April 2014
Hackable URIs may look nice, but they don’t have much to do with REST and HATEOAS
“Hackable” URIs are constructed according to a clear pattern and are a standard feature of any self-respecting, SEO-friendly website. They can be a used as a navigation device that makes it easier to identify the current resource and determine how to access other resources.
In considering URIs from a web usability perspective, Jakob Nielsen suggested that URIs are actually part of a website’s UI. They help to visualise the site structure and allow users to move to higher levels of the information architecture by hacking off the end of a URI.
This idea of the URI as an interface device is often applied to HTTP-based APIs, allowing developers to navigate the information structure by adjusting the URI. However, this becomes irrelevant to a fully RESTful API that has adopted HATEOAS (Hypertext As The Engine Of Application State) to the point where it can even be counter-productive to expose them.
What difference does HATEOAS make?
Adopting HATEOAS implies a fundamental shift in the way that developers should be using the API. For non-HATEOAS APIs, a developer is responsible for constructing the resource URI given the documentation available to them. In this context, it makes sense to improve the usability of your API by providing a consistent and predictable URI structure.
However, the point of HATEOAS is that it takes this responsibility away from developers. The API becomes self-describing in that it provides all the links that a consumer will need to manipulate resources. The consumer can navigate the API via links embedded in resources rather than having to directly manipulate any URIs.
This makes it easier for consumers to discover the features available in the API and consume them correctly. Ideally, the only URI a consumer will ever have to construct is the base URI for the API. From there on they should be navigating around the API wholly on the links it provides.
The problem of enforcement
A major advantage of this approach is that the URI scheme is de-coupled from the actual resource representations. Servers have complete control over the resource addressing and you can change your URIs without breaking your consumer integrations.
Well, that’s the theory.
The reality is that not all consumers will play ball. A problem with HATEOAS-based APIs is that there is no way to enforce proper usage. Consumers will construct the URIs manually if they want to and you cannot stop them. After all this is the path of least resistance in that it is what they are accustomed to and it does involves slightly less work in the short term.
What’s worse is that after having integrated with the API in the wrong way they will complain when changes to the URI schema result in broken links. You have all the overhead of creating a HATEOAS API without being able to realise the benefit of de-coupled URIs.
One way of preventing this misuse is to make URLs opaque. Therefore, a resource URI like http://myapi.com/products/12345 would be presented to the user as http://myapi.com/DTSVSBGWEFDTYCXJNHBNI8.
Even discounting the extra burden this would place on servers, this approach feels a little like shooting yourself in the foot. Developers like the readability of URIs and the assurance that they are accessing the right resource. You may be forcing them to integrate in the way that you want, but this will damage perceptions over the usability and accessibility of your API.
URI design should be irrelevant
There are some real advantages to adopting HATEOAS. You get reduced client coding errors caused by malformed URIs or inappropriate method calls. It also provides for de-coupling between server and client that allows you to evolve your API without breaking existing integrations. However, this can only be realised if your consumers are interacting with your API in the way you intended.
There’s no harm in implementing hackable URIs in a RESTful API. It’s what developers expect to see when they debug code. It’s also the default scheme provided by implementation tools such as WebAPI so in many cases it’s more effort not to provide them.
The point is that they should be irrelevant if developers are consuming your API correctly. They will never need to construct an URI beyond the initial root of your API. Ultimately, the only way to ensure this is to support your integrators with the right level of tooling, documentation and examples. This puts you in a stronger position to deflect complaints when consumers have failed to conform to your clear guidance.