Examples

From Ocean Framework Documentation Wiki
Jump to: navigation, search

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
  • GET to obtain the list of all items in the basket.
  • POST to add an item to the basket. Returns the new item.
  • PUT to replace the list of items in the basket. Returns the updated basket.
  • DELETE to remove all items from the basket. Returns the updated basket.
payment
  • GET to obtain the payment details,
  • POST in order to proceed to checkout. Returns the updated basket.
  • PUT to change payment details. Returns the updated basket.
  • DELETE to revert the payment. Returns the updated basket.

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.

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.