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.
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
<?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.
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.
Some comments by Roy Fielding
ReplyDeletehttp://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven