Love to HATEOAS
Hypermedia for Fun and Profit →
Gabe Sullice
Senior Engineer - Acquia Octo
JSON API co-maintainer
HTTP/2 enthusiast
Specification-junkie
Loses lots of sleep over API design
HTTP
It's the Hypertext Transfer Protocol
and that's a protocol layer sitting atop the TCP/IP network protocols
And there are many such protocols.
SMTP, POP & IMAP
SSH
FTP
IRC
& XMPP
SOAP
HTTP IS AN APPLICATION Language
Understanding HTTP
HTTP is an application protocol for distributed, collaborative, and hypermedia information systems.
URis, METHODS, and messages
- Resource - A unit of information
- URI - Uniform Resource Identifier
- Method - GET, POST, PATCH, DELETE & others
- Status - 200, 300, 400, 500 inter alia
- Messages - "Requests" and "Responses"
URI
UNiform resource Identifier
Almost always a URL
Which is simply a unique identifier that can be "located"
http://example.com/api/user/1
"http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
Methods
GET, POST, PATCH, PUT & DELETE
Describe "actions" on a resource
HEAD & OPTIONS are about information discovery
GET - Show me the identified resource
POST - Add this resource
PATCH - Update the identified resource with this information
PUT - Replace the identified resource with this one
DELETE - Remove the identified resource
HEAD - Is there a resource with this identifier?
OPTIONS - What actions can I take on a resource?
Statuses
200, 300, 400, 500
Categorize communication into conversational buckets
200 - Understood
300 - Maybe you meant X?
400 - Sorry, I don't understand
500 - It's not you, it's me
Messages
requests and responses
Contains a start line (URI + Method/Status), headers & body
Headers describe the resource
Content-Type: text/html <html> <title>Gabe Sullice</title> <body>stout</body> </html>
Content-Type: application/json { "type": "user", "id": 1, "attributes": { "name": "gabesullice" } }
Request
GET www.example.com/user/1 HTTP/1.1
response
HTTP/1.1 200 OK
Content-Type: application/json { "type": "user", "id": 1, "attributes": { "name": "gabe" } }
REST
Representational State transfer
not a protocol
REST is an architectural style that defines a set of constraints and properties based on HTTP.
Bad News
Hypermedia API
Principles
- Client-Server
- Stateless
- Cache
- Layered System
- Code-on-Demand
- Uniform Interface
Client-server
A separation of concerns
Client handles presentation
Server handles data storage
Foundational principle for "decoupled" sites
STateless
Every request/response is independent
Cacheability
A response should contain information to govern its own intermediate storage
Its purpose is to eliminate requests/responses cycles or to reduce the time it takes for that cycle to complete (latency)
layered system
The system should be indifferent to proxies, load balancers, CDNs, etc.
COde-on-demand
Optional.
Useful when a client does not have the know-how on how to process a resource. It sends a request to a remote server for the code representing that know-how, receives that code, and executes it locally.
Uniform Interface
Entity representations are decoupled from their storage.
Hypermedia is the engine of application state.
HYPERmedia
Hyper text
I'm a teapot, short and stout
✷Hyper✷text✷
<a href="https://httpstatus.es/218">I'm a teapot</a>
Hypermedia
{ "type": "joke", "id": 1,
"attributes": {
"content": "I'm a teapot"
},
"links": {
"explanation": "https://httpstatus.es/218"
}
}
Hypermedia JUST means media with links
A link?
A link is soo much more than that clickable blue text.
A LINK CAN BE VIEWED AS a statement
It takes the form:
"{this URI} has a {relation type} resource at {that URI}, which has {target attributes}".
RElation Type
A link relation type identifies the semantics of a link.
Example:
<a rel="help" href="http://foo.com/guide">
<a rel="my-cart" href="http://foo.com/cart/4">
Target attribute
Hints information about the linked-to resource.
Example:
<a rel="help" hreflang="en, fr, es" href="http://foo.com/guide">
<a rel="my-cart" title="Checkout" href="http://foo.com/cart/4">
Hypermedia ➡ Web
index.html
index.html
hero.jpg
index.html
style.css
hero.jpg
index.html
style.css
url('https://www.example.com/assets/separator.svg');
hero.jpg
index.html
style.css
url('https://www.example.com/assets/hipster-heavy.ttf');
url('https://www.example.com/assets/separator.svg');
hero.jpg
/home
/posts
/posts/2
/posts/1
/about
/home
/posts
/posts/2
/posts/1
/about
/posts
/posts/2
/posts/2/tags
/posts/2/author
/posts/1
/posts
/posts/2
/posts/2/tags
/posts/2/author
/posts/1
/posts/2
/posts/2/author
/posts/2/tags
/tags/2
/tags/1
/api/content
/api/schemas/content
/api/content?page=2
/api/posts/1/comments
/api/content
/api/schemas/content
/api/content?page=2
/api/content?page=3
/api/posts/2/comments
/api/posts/1/comments
/api/content
/api/schemas/content
/api/content?page=2
/api/content?page=3
/api/content?page=4
/api/posts/2/comments
/api/posts/1/comments
Difficult QUESTIONS IN API DESIGN
- How many pages are there?
- Am I allowed to delete this resource?
- Is my shopping cart empty?
- Can I make a bank withdrawal?
- What URL structure should I use?
- How do I use "pretty" URLs in my application?
- How do I represent variations of single entity?
- How do I add an item to my cart?
We can drive client-server interaction through Hypermedia
HATEOAS
Hypermedia As The Engine Of Application State
HATEOAS
is like
HYperDrive
for your APIs
Hypermedia can provide
related Resources
Hypermedia can provide
Availale variants
Hypermedia can provide
Availale Actions
Related REsources
- Previous and next pages of a collection
- First and last pages of a collection
- An entity's author
- Similar products
- Contextual resources, like tags or categories
Available Variants
- Revisions
- Translations
- Product variants
- Small, Medium & Large
- Red, Green or Blue
Available Actions
- Add
- Remove
- Revise
- Purchase
- Pay
- Relate A to B
Example Time
{
"data": [...],
"links": {
"next": "https://foo.com/collection?page=1",
"last": "https://foo.com/collection?page=10"
},
}
{
"data": [...],
"links": {
"self": "https://foo.com/birds",
"family#0": {
"href": "https://foo.com/birds/paradisaeidae",
"meta": {
"title": "Birds of Paradise"
}
},
"family#1": {
"href": "https://foo.com/birds/corvidae",
"meta": {
"title": "Crows, Ravens & Jays"
}
}
}
}
{
"data": [...],
"links": {
"self": "https://foo.com/shirt/1",
"product-variant#0": {
"href": "https://foo.com/shirt/1/a",
"color": "#0033ff",
"title": "Marine"
},
"product-variant#1": {
"href": "https://foo.com/shirt/1/b",
"color": "#ee0000",
"title": "Ruby"
}
}
}
{
"data": [{
"type": "post",
"id": 1,
"attributes": {...},
"links": {
"self": "http://foo.com/post/1?resource_version=id:27",
"latest-version": "http://foo.com/post/1?resource_version=id:29"
}
}, {
"type": "post",
"id": 2,
"attributes": {...},
"links": {
"self": "http://foo.com/post/21?resource_version=id:13",
"latest-version": "http://foo.com/post/2?resource_version=id:13"
}
}]
}
{
"data": [{
"type": "post",
"id": 1,
"attributes": {...},
"links": {
"self": "http://foo.com/post/1",
"operation#0": {
"href": "http://foo.com/post/1",
"meta": {
title: "Edit",
rel: "edit"
}
},
"operation#1": {
"href": "http://foo.com/post/1",
"meta": {
title: "Delete",
rel: "drupal://link-relation/jsonapi/remove"
}
}
}
}]
}
{
"data": [{
"type": "product",
"id": 1,
"attributes": {...},
"links": {
"self": "http://foo.com/product/1",
"cta": {
"href": "http://foo.com/cart/4",
"meta": {
title: "Add to Cart",
rel: "drupal://link-relation/jsonapi/relate",
template: {
"method": "POST",
"body": "{\"type\": \"product\", \"id\": 1}"
}
}
}
}
}]
}
{
"data": [{
"type": "product",
"id": 1,
"attributes": {...},
"links": {
"self": "http://foo.com/product/1",
"cta": {
"href": "http://foo.com/wishlist/5",
"meta": {
title: "Add to Wishlist",
rel: "drupal://link-relation/jsonapi/relate",
template: {
"method": "POST",
"body": "{\"type\": \"product\", \"id\": 1}"
}
}
}
}
}]
}
Love to HATEOAS: Hypermedia for Fun and Profit
By Gabriel Sullice (Gabe)
Love to HATEOAS: Hypermedia for Fun and Profit
- 1,035