[H]ypermedia [a]s [t]he [E]ngine [o]f [A]pplication [S]tate
Standard/Specification on how servers and clients interact
Initial user feedback
Known hypermedia specifications:
Purpose:
Last update: 2015-05-29
Extendable
Get a specific order
GET /orders/1 HTTP/1.1
Accept: application/vnd.api+json
{
"data": null,
"errors": null,
"meta": null,
"links": null,
"included": null,
"jsonapi": null
}
{
"data": {
"id": "1",
"type": "order",
"links": {
"self": "/orders/1"
},
"attributes": "...",
"relationships": "..."
}// ...
}
{
"data": {
"id": "1",
"type": "order",
"links": "...",
"attributes": {
"order-id": "1",
"order-number": "1010101010",
"shipment-number": "1012121212",
"status": "approved"
},
"relationships": "..."
}// ...
}
{
"data": {
"id": "1",
"type": "order",
"links": "..."
},
"attributes": "...",
"relationships": {
"order-items": {
"data": [
{"id": 1, "type": "order-item"},
{"id": 2, "type": "order-item"}
],
"links": {
"related": "/orders/1/items"
}
}
}
}
{
"data": {
"id": "1",
"type": "order",
"links": "...",
"attributes": "...",
"relationships": "..."
},
"meta": {
"order-items-count": 2,
"order-lines-count": 3,
"full-order-price": "1000"
}
}
Siren is a hypermedia specification for representing entities.
Last update: 2015-10-21
Entity consits of:
Get a specific order
GET /orders/1 HTTP/1.1
Response: application/vnd.siren+json
Define entitiy's purpose.
{
"class": [ "order" ],
"title": "",
"properties": {},
"entities": [],
"links": [],
"actions": []
}
Descriptive text about the entity.
{
"class": [],
"title": "An order entity which represents the top level order.",
"properties": {},
"entities": [],
"links": [],
"actions": []
}
A set of key-value pairs describing the state of the entity.
{
"class": [],
"title": "",
"properties": {
"order-id": "1",
"order-number": "1010101010",
"shipment-number": "1012121212"
},
"entities": [],
"links": [],
"actions": []
}
A collection of related sub entities. Important part is the relation between the parent and a child entity.
{
"class": [],
"title": "",
"properties": {},
"entities": [
{
"class": [ "items", "collection" ],
"rel": [ "/rels/order-items" ],
"href": "/orders/1/items"
}
],
"links": [],
"actions": []
}
Non-entity based relation bound to the entity.
{
"class": [],
"title": "",
"properties": {},
"entities": [],
"links": [
{
"rel": [ "self" ],
"href": "/orders/1/"
}
],
"actions": []
}
A collection of actions that can change the state of the entity.
{
"class": [],
"title": "",
"properties": {},
"entities": [],
"links": [],
"actions": [
{
"name": "update-order-status",
"title": "Update an order status",
"method": "POST",
"href": "/orders/1",
"type": "application/json",
"fields": [
{ "name": "status", "type": "radio", "value": "approved" }
]
}
]
}
Hypertext Application Language
Last update: 2013-09-18
Get a specific order
GET /orders/1 HTTP/1.1
Accept: application/hal+json
{
"_links": {
"self": { "href": "/orders/1" }
},
"_embedded": {},
"order-id": "1",
"order-number": "1010101010",
"shipment-number": "1012121212"
}
{
"_links": {},
"_embedded": {
"items": [{
"_links": { "self": { "href": "/orders/1/items/1"}},
"order_item_id": "1"
}]
},
"order-id": "1",
"order-number": "1010101010",
"shipment-number": "1012121212"
}
{
"meta": {
"count": 3
},
"data": [
{
"type": "order",
"id": "1",
"attributes": {
"order-number": "1010121312379",
"shipment-number": "1010123123",
"status": "approved"
}
},
{
"type": "order",
"id": "2",
"attributes": {
"order-number": "1010121312380",
"shipment-number": "1010123124",
"status": "approved"
}
},
{
"type": "order",
"id": "3",
"attributes": {
"order-number": "1010121312381",
"shipment-number": "1010123123",
"status": "initial"
}
}
],
"links": {
"self": "/orders?page[cursor]=XYZ0",
"first": "/orders?page[cursor]=XYZ0",
"prev": null,
"next": "/orders?page[cursor]=XYZ1",
"last": "/orders?page[cursor]=XYZN"
}
}
{
"class": [ "orders", "collection" ],
"title": "A list of orders",
"properties": {},
"entities": [],
"links": [
{ "rel": [ "self" ], "href": "/orders/1/" },
{ "rel": [ "first" ], "href": "/orders?page[cursor]=XYZ0" },
{ "rel": [ "next" ], "href": "/orders?page[cursor]=XYZ1" },
{ "rel": [ "last" ], "href": "/orders?page[cursor]=XYZN" },
],
"actions": []
}
{
"_links": {
"self": { "href": "/orders/1/" },
"first": { "href": "/orders?page[cursor]=XYZ0" },
"next": { "href": "/orders?page[cursor]=XYZ1" },
"last": { "href": "/orders?page[cursor]=XYZN" },
},
"_embedded": []
}
Sorting is not directly a part of HATEOAS.
Best practice:
GET /orders?sort=-created_at,status HTTP/1.1
Filtering is not directly a part of HATEOAS.
Best practice:
GET /orders?status=initial HTTP/1.1
Team decision / Open discussion