In 2011 mnot wrote about json linking. Now it's like 4 years later and time to take a look at the link formats in json, which are used by lots of people.

In HTML5 we have a <link> tag defined like this:

<link rel= "author license" href= "/about" >

The attributes of this link are defined like this (taken from the W3C-page):

href — Address of the hyperlink

crossorigin — How the element handles crossorigin requests

rel — Relationship between the document containing the hyperlink and the destination resource

media — Applicable media

hreflang — Language of the linked resource

type — Hint for the type of the referenced resource

sizes — Sizes of the icons (for rel="icon")

Also, the title attribute has special semantics on this element: Title of the link; alternative style sheet set name.

The advantage of the <link> tag in XML is, that you could put it anywhere in your document (like the <a> tag in HTML). If you want to achieve web linking (rfc5988) in JSON, there are multiple approaches.

This post shows some of the widely used JSON media types and how they deal with links. I will have a short look at HAL, Collection+JSON, Hydra/JSON-LD, Mason, Siren and UBER. Example files for all of them are in this json links gist.

Disclaimer: In the previous years I implemented HAL or several custom JSON based APIs. Most information in this post is gathered from the official pages of each media type. If you find some incorrect usage or better way to do something, please tell me!

Links vs. Actions

In an interesting thread on the hypermedia-web mailinglist Mike Amundsen explains that the links/queries/template in Collection+JSON have a special meaning:

items[].href for parameterless read-only navigation

for parameterless read-only navigation link[] items for parameterless read-only navigation

items for parameterless read-only navigation queries[] items for paramaterized read-only navigation

items for paramaterized read-only navigation template{} item is for paramaterized write navigations

Other media types (like e.g. HAL) don't make this distinction and use links for read and write navigation with parameters and without.

Some media types introduce a concept of actions (Mason, Siren, UBER) or hydra:supportedOperation in Hydra/JSON-LD. In my understanding those actions are what template{} is in Collection+JSON.

A special links property

One approach is to use plain JSON (with your data) and add an extra _links , @links or links property. Depending on the approach this links property contains an object (with relation as key of that object) or an array of multiple so called link objects.

Handling the "rel" property

HAL: the key of the _links object is the name of the relation.

of the object is the name of the relation. Collection+JSON and Siren: the links property is always an array and the relation is defined as rel -property of the link item

property is always an array and the relation is defined as -property of the link item Mason: the key of the @links object is the name of the relation.

of the object is the name of the relation. jsonapi: the key of the links object is the name of the relation.

of the object is the name of the relation. UBER: The rel -key of the link item is always an array of relations for the link

Inn UBER, Collection+JSON and Siren the rel is NOT the key of the object. This has the advantage, that one can put multiple relations on one link (e.g. think of a first-page link, which is also a prev-page link if you are on the second page). If you want to have multiple links to the same entity in e.g. HAL, you would define a _links key first and a _links key prev , which contain the same reference.

Handling the "href" property

Collection+JSON, HAL, Mason, Siren and UBER: the href of a link item is the link to the referenced resource.

of a link item is the link to the referenced resource. jsonapi: the link item is a string which represents the href or a link object. The link object has an id and type property (see the docs)

Extra Type for Links in Hydra/JSON-LD

Hydra for JSON-LD uses a different approach. The href is represented as string value of the target url (e.g. "register_user": "/users/register" and the @context is used to describe the properties of the json. The hydra:Link property (imported from http://www.w3.org/ns/hydra/core#), describes the link.

Special data Property in UBER

In UBER, every content is placed in a data array. That's why a link object can appear everywhere in the data array. A Link looks like this: {"rel" : ["self"], "url" : "http://example.org/"} in UBER. So rel and url have a special meaning in UBER's data objects.

Properties, which are not Links

HAL: only _links and _embedded are reserved words: everything else is a plain old javascript object

and are reserved words: everything else is a plain old javascript object Collection+JSON: Every item has to be in a collection.items array. The item has a data array. These data items have a name and a value property.

array. The item has a array. These data items have a and a property. Hydra/JSON-LD: Since JSON-LD defines the semantics within the @context - the rest of the response can be treated as a plain json object.

- the rest of the response can be treated as a plain json object. jsonapi: the special property data (next to links ) is always an array and contains plain json data (and type , id and links )

(next to ) is always an array and contains plain json data (and , and ) Mason: Only the @ -prefixed properties like @links are reserved. Everything else is a plain json object.

-prefixed properties like are reserved. Everything else is a plain json object. Siren: Properties are stored as key value in a special properties property.

property. UBER: The generic data key contain data items with a name and a value property.

Actions

Defining actions

HAL: Actions and Links are the same thing in HAL and are stored in _links object.

object. Collection+JSON: Has a special template object, which defines which fields to send on POST/PUT.

object, which defines which fields to send on POST/PUT. Hydra/JSON-LD: Within the hydra:Link property there is a special supportedOperation object.

property there is a special object. jsonapi: As far as I can see, jsonapi treats actions and links the same (like HAL).

Mason: Has a special @actions property, which is similar to the @links property.

property, which is similar to the property. Siren: Has a special actions property as an array, which is similar to the links property.

property as an array, which is similar to the property. UBER: The data item may have a action property, which indicates a possible an action

Describing allowed/expected HTTP methods

HAL: By design it does not describe the possible methods on a linked resource.

Collection+JSON: The method cannot be specified in the template object.

object. Hydra/JSON-LD: The possible operations (e.g. POST ) are defined in the hydra:supportedOperation object.

) are defined in the object. jsonapi: As far as I can see, jsonapi does not describe the possible methods on a linked resource.

Mason: The @actions items have extra properties like schemaUrl or type to indicate what should be send to this target. Usually POST is expected as request method.

items have extra properties like or to indicate what should be send to this target. Usually POST is expected as request method. Siren: The actions items have an additional method property, which contains the HTTP method (e.g. "POST" ).

items have an additional property, which contains the HTTP method (e.g. ). UBER: The action property of the data item may contain "append", which is mapped to HTTP's POST

Conclusion

There have been approaches like JSON Reference, which defines a link as { "$ref": "http://example.com/example.json#/foo/bar" } , but if one compares that with the media types of this post, it's basically very limited to have only a $ref property defined :).

Even though URI templates have a wide acceptance as template language for query strings, there are also some media type specific approaches to build HTML-Form-like behaviour in JSON. For example with HALO on top of HAL, with Collection+JSON's prompt property or with Siren's actions[n].fields[m].type property to make generic browsers easier to create.

Except in case of Siren's class property, you need some thing like a Profile Link Relation Type (rfc6906) to indicate of what type your returned entity is.

In my experience traversing the links does require a generic client library, especially if you write the M2M client library for a service of someone else. For example even though it looks simple in the case of HAL, but you can fetch href of first linked entity in this way: response._links.item.href OR response._links.item[0].href . Which of them is currently right, depends only on the server.

If one compares the media types (look at the examples at this json link gist) it's easy to see that there is no right or wrong way.

If you decide about using a media type, please checkout the great documentation for each of those media types and evaluate the media types before you roll your own media type and stick to just application/json !