Let us examine a hypothetical API in some detail. A central resource to our system is the shopping basket. It is represented by a JSON object which can be retrieved by a
GET to a URI made known by documentation or discovered via a hyperlink in some other resource. The URI represents the resource, a noun: in this case a shopping basket.
The standard HTTP methods represent verbs for conventionalised actions on a resource. For instance, a
GET retrieves a JSON representation of the resource. A
POST request to the same URI creates a new basket. A
PUT operation updates the basket in some meaningful way, and a
DELETE request destroys it. Create/Retrieve/Update/Destroy - CRUD.
These four HTTP method verbs (
DELETE) can be combined with any hyperlink URI found in a RESTful resource representation. This means that such hyperlinks are compact and expressive. Resources will not be littered with unnecessarily long lists of actions that can be performed on them. It is clear at once to all clients what can be done with a resource given its basic URI, which is always present as a hyperlink with a
The API must also provide means of adding and removing items from the basket and for payment for those items. The Basket service API therefore defines hyperlink tags for these purposes:
The API documentation for the basket service will state the basic basket URI, such as “
https://apis.example.com/v1/baskets”. It will also describe all fields in the returned basket resource JSON representation, including the meaning of the hyperlinks and the HTTP verbs they accept. It will also describe the states of the basket resource for which each link will appear. For instance, the
payment hyperlink isn’t present when payment isn’t an option (perhaps due to the fact that the basket is empty, or to the presence of invalid items).
A new basket item is created by
POSTing to the
items hyperlink. You may wonder how an item is removed from the basket. Your first guess might be that the client must first obtain the list of all items using a
GET to the
items hyperlink, delete the item to be removed from the list, and then do a
PUT to the
items hyperlink with the updated list of items. This would work, but it’s unnecessarily complicated.
A much easier way is provided by the item resource itself, returned from the
POST that created it. To delete the item, simply do a
DELETE to its
self hyperlink. This will remove it from its basket: the hyperlink URI will contain all necessary context.
An API carefully designed according to these principles provides extraordinary freedom for both the server and the client side in that it decouples them in a particular way. This allows the code to evolve without the contract between server and client having to change.
For this reason, clients are prohibited from constructing URIs. They may add query arguments where applicable, but that’s all. Instead they follow the provided hyperlinks in the JSON resource representations passed back and forth. They will always contain all possible next steps.
Resource representations may be saved by clients for later re-use. If the API has been updated in the interim, built-in versioning will make sure the correct API version is used in the requests.
Hyperlinks may also provide other abstractions. For instance, there may be hyperlinks to follow a relation: an item may contain a hyperlink by which its basket may be retrieved.
Another example is paginated lists of search results. It’s often practical to include hyperlinks in a search result to the next and previous page. A simple
GET to such a hyperlink would retrieve the adjacent page. This frees the client from having to know conventions for query arguments to control page size, etc.
Evolving Service Structure
It’s not unlikely that at some point the basket checkout for some reason needs to be moved to a different service. In a system following HATEOAS conventions, this is easy. All that needs to be done is for the basket service to return a different
payment hyperlink pointing to the new checkout service. As the client always treats the hyperlinks as black boxes, the transition will be seamless. The client won’t even need to be updated.
Introducing VIP Baskets
Another situation would be the introduction of “VIP shopping baskets”. This is easily handled by the basket service returning a new
self hyperlink for baskets with VIP status. Again, clients don’t have to be updated and the transition is seamless.
Sharding a Resource
Yet another possibility, with HATEOAS, is the situation where the number of resources of a certain kind - such as the number of users - has become so high that processing of the resources has to be distributed over several dedicated servers according to some criterion. Again, this can be done transparently and without any change to clients by the User Service returning personalised