dracoblue.net

Overview of JSON Hypermedia Link Formats

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
  • link[] items for parameterless read-only navigation
  • queries[] 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.
  • Collection+JSON and Siren: the links property is always an array and the relation is defined as rel-property of the link item
  • Mason: the key of the @links object is the name of the relation.
  • jsonapi: the key of the links 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.
  • 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
  • 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.
  • 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.
  • jsonapi: the special property data (next to links) is always an array and contains plain json data (and type, id and links)
  • Mason: Only the @-prefixed properties like @links are reserved. Everything else is a plain json object.
  • Siren: Properties are stored as key value in a special properties 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.
  • Collection+JSON: Has a special template object, which defines which fields to send on POST/PUT.
  • Hydra/JSON-LD: Within the hydra:Link property there is a special supportedOperation 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.
  • Siren: Has a special actions property as an array, which is similar to the links 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.
  • Hydra/JSON-LD: The possible operations (e.g. POST) are defined in the hydra:supportedOperation 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.
  • Siren: The actions items have an additional method property, which contains the HTTP method (e.g. "POST").
  • 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!

PS: If you don't want to have links in your JSON at all, the rfc5988 defines also special Link headers.

Give something back

Were my blog posts useful to you? If you want to give back, support one of these charities, too!

Report hate in social media Campact e.V. With our technology and your help, we protect the oceans from plastic waste. Gesellschaft fur Freiheitsrechte e. V. The civil eye in the mediterranean

Recent Dev-Articles

Read recently

Recent Files

About