Examples
Contents
Shopping Basket
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 (POST
, GET
, PUT
, 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 ref
of “self”
.
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:
Hyperlink tag | Actions |
---|---|
items |
|
payment |
|
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 POST
ing 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.
Related Resources
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 self
hyperlinks.