Thursday, March 14, 2013

HATEOAS - HyperMedia as the Engine of Application State



What does  HATEOAS mean ?

It means that Hypermedia should be an engine of Application state. Using hypermedia is a powerful tool to propagate the navigation from a particular representation state of a resource. It is a powerful way if decoupling Clients and Server concerns.

This Constraint of REST gives the APIs a way to change and evolve, independent of the Client code. Hence even the Client code can independently change. It is also a Shield against Applications ( APIs ) against becoming Rpc-Oriented

What does that mean ?
How can HATEOAS be actually implemented ?

HATEOAS , implies that, Client  interact with Link relationships, which in turn defines all the immediate navigations possible , as well as all the actions possible at a particular Application State, instead of interacting with hard-coded URIs.

Let's start with an Example of a Simple Issue Tracker, An application to track issues , a miniature version of Issue Tracker
An user logs in and creates Issues within a department. Each issues has comments linked to it.

Resource Identified are :

















URI for user : /user
Complete URL : http://api.tracker.com/user


Some Use cases for User , that will help to determine the Links and Relationships and hence acts as a
Navigation Guide for the different Application States

Request to Fetch list of departments:

curl --request OPTIONS http://api.tracker.org/department

Response:

HTTP/1.1 200 OK
Date: ...
Allow: OPTIONS, GET, POST, PUT, DELETE
Content-Length: 0

 This response list the permitted HTTP operation for 'Department' Resource
i.e GET, POST , PUT and DELETE

The different Media-types definitions for 'Department' resource must be provide by the API provider
and Client keeps a local Map of the Media types vs the Client Code Object

Like if the Media-type supported is 'application/xml' then Client may have a Jaxb class corresponding to the Xml schema, which represents a Resource Representation for the 'department'.

Client now interact with 'department' via GET, POST, PUT or DELETE operations via a particular representation defined by the Media-type

So far so good.
 But the Question now is how should Client mover further from 'department' ?
How should he find out other Link Relationships for 'department' ?

Instead of looking at the Docs and finding out what other operations are permitted, Client instead can use Response from 'GET http://api.tracker.org/departments' to navigate further

Request :

curl --request GET http://api.tracker.org/departments


Response :

HTTP/1.1 200 OK

Content-type: application/xml;charset=UTF-8

Date: ....


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<departments>

 <department id="dept_001">
  <name>department_001</name>
  <type>engineering</type>
  <created-date>.....</created-date>
  <last-modified-date>....</last-modified-date>
  <link rel="self" href="http://api.tracker.org/department/dept-001" />
  <link rel="issues" href="http://api.tracker.org/department/dept-001/issues" />
 </department>

 <department id="dept_001">
  <name>department_001</name>
  <type>engineering</type>
  <created-date>.....</created-date>
  <last-modified-date>....</last-modified-date>
  <link rel="self" href="http://api.tracker.org/department/dept-001" />
  <link rel="issues" href="http://api.tracker.org/department/dept-002/issues" />
 </department>

</departments>

This response lists down all the Departments. Each department has two link relationships.

1. <link rel="self" href="http://api.tracker.org/department/dept-001" />

This rel="self" tells the client that this a link of the type 'department' i.e one particular department in the collection of departments.

2. <link rel="issues" href="http://api.tracker.org/department/dept-001/issues" />

This rel="issues" tells the client that this is the link to the issues that can be connected from this department.

This approach allows the client eases the coupling constraints wit the server side implementations.

Other approach, which is more tightly coupled approach, would be , where the client would have to maintained a list of all the URIs at client-side, with almost hard coded URIs or a scheme for URI cooking !!

Like the above response from server could also be designed as

<departments >

<department id="dept_001">
  <name>department_001</name>
  <type>engineering</type>
  <created-date>.....</created-date>
  <last-modified-date>....</last-modified-date>
  <link rel="self" href="http://api.tracker.org/department/dept-001" />
 </department>

 <department id="dept_001">
  <name>department_001</name>
  <type>engineering</type>
  <created-date>.....</created-date>
  <last-modified-date>....</last-modified-date>
  <link rel="self" href="http://api.tracker.org/department/dept-001" />
 </department>

</departments>

In this Response, <link rel="issues" ... /> is missing. Client now uses an URI cooking scheme to create an issue.

URI cooking for Issues:
URI Issues = URI department + department-id + "issues"

The problem with this approach is that URI manipulation is left to the client. As the resources are
under constant modifications , so its quite possible that in near future a different URI scheme may come into being, from API provider.

Suppose such a changes happens, URIs are now also contain a version name, 'v11' in this case. Let the  new URI scheme is represented as

New URI cooking scheme for Issues :
URI issues = v11 + issues

Client will now have to modify his application to move to this new scheme. The worst part of this change is that the client
needs to figure out precisely what are the other resources that are related to "issues". Code, now,  must be modified across the entire client application, at all concerned places.

This is one of the Orientations of a Tight Coupling between client and server !!!

 To REDUCE the constraints of this Coupling, one of the most misunderstood and least implemented constraint of REST should be used. 'HyperMedia as the Engine of Application State', popularly spelled as 'HATEOAS'

This can be achieved by using Link relationships like
<link rel="issues" href="http://api.tracker.org/department/dept-001/issues" />

HATEOAS , thus implies that, Client  interact with Link relationships, which in turn defines all the immediate navigations possible , as well as all the actions possible at a particular Application State, instead of interacting with hard-coded URIs.

So the client now extracts the Link with attribute rel = 'issues'
It no longer has to bother about URI cooking scheme. This responsibility is left to the sever to return the right URI for "issues". Client should simply extract that link and use the corresponding 'Media-Type' to interact with 'issues' resource.


1 comment:

  1. Some comments by Roy Fielding

    http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

    ReplyDelete