JSON Linking with HAL

Since the discussion about links in JSON seems to be opening up, I thought I would briefly explain my take on linking with JSON and how that presents itself in the design of HAL.

We need a media type (the HTML of machines), not another XLink

We need a general purpose media type, which extends JSON, that can be used as a standard way to represent a resource and its relations to other resources on the Web.

It’s very important, particularly because we are talking about JSON, that this media type be simple in its design. There are only three essential capabilities for representing resources that this media type needs deliver:

  1. Representing resource state
  2. Linking to other resources
  3. ‘Containment’ of embedded resources

HAL (application/hal+json) is a media type designed for this purpose, and here’s how it provides the above capabilities:

Representing resource state

A resource in HAL is just a plain old JSON object with whatever properties you want, so it’s the same way of using JSON you’re doing right now:

{ "name": "A product", "weight": 400, "dimensions": { "width": 100, "height": 10, "depth": 100 }, "description": "A great product" }

Linking to other resources

HAL provides its linking capability with a convention which says that a resource object has a reserved property called “_links”. This property, surprisingly enough, is an object that contains links. These links are key'ed by their link relation, e.g. self, next, product, customer, etc:

{ "_links": { "self": { "href": "/product/987" }, "upsell": [ { "href": "/product/452", "title": "Flower pot" }, { "href": "/product/832", "title": "Hover donkey" } ] }, "name": "A product", "weight": 400, .. *snip* .. }

Where a relation may potentially have multiple links sharing the same key (e.g. the 'upsell’ relation in the above example), the value should be an array of link objects:


Where a relation will only ever have one link (e.g. the 'self’ relation), the value can just be a straight link object:


'Containment’ of embedded resources

In some situations it’s more efficient to embed related resources rather than link to them, as it prevents clients from having to make extra round trips. HAL provides this capability with a convention which says a resource has another reserved property “_embedded”. This property is similar to _links in that embedded resources are key'ed by link relation - the difference is that, instead of link objects, the values are resource objects again which produces an elegant, recursive model. The idea being that a recursive model will help a lot when dealing with partials on the server side, and provide consistency on the client side.

The key aspect of these embedded resources is that they reset the context of any resource state and links which they contain. i.e. a link inside an embedded resource implicitly relates to that embedded resource and not the parent.

{ "_links": { .. *snip* .. }, "_embedded": { "manufacturer": { "_links": { "self": { "href": "/manufacturers/328764" }, "homepage": { "href": "http://hoverdonkey.com" } }, "name": "Manufacturer Inc." }, "review": [ { "_links": { "self": { "href": "/review/126" }, "customer": { "href": "/customer/fred", "title": "Fred Wilson" } }, "title": "Love it!", "content": "I love this product. I also bought a Hover Donkey with it.", "rating": 10 }, { "_links": { "self": { "href": "/review/178" }, "customer": { "href": "/customer/tom", "title": "Tom Dee" } }, "title": "Hate it!", "content": "My hover donkey choked on it. DO NOT BUY!1!!", "rating": 0 } ] }, "name": "A product", "weight": 400, .. *snip* .. }

The same rules apply with regard to the cardinality of embedded resources as to links e.g:

_embedded.review[1].rating _embedded.manufacturer.name _embedded.review[0]._links.customer.title _embedded.manufacturer._links.homepage.href

Finally, here’s a visual representation of HAL’s information model:

Here’s where you can learn more about HAL: