Skip to content

Instantly share code, notes, and snippets.

@miyagawa
Created February 26, 2012 02:53
Show Gist options
  • Save miyagawa/1912431 to your computer and use it in GitHub Desktop.
Save miyagawa/1912431 to your computer and use it in GitHub Desktop.
How to represent Links in REST

How to embed HATEOAS/Link inside JSON

HTTP Headers

For HTTP headers it's quite straightforward: draft-nottingham-http-link-header defines this.

Link: <http://example.com/>; rel="previous"; titile="Previous chapter"

Perl's LWP library automatically parses this headers, and in Ruby there's link_header gem.

Implemented in GitHub API v3.

RESTful JSON response

There's a couple of ways to embed links inside a JSON data structure. Here's the list I can come up with:

rel as a key, url as a value

{
  "id": 1234,
  "name": "Bob",
  "links": {
    "self": "/people/1234"
  }
}

Pros:

  • Simple. Easy to parse and access in client libraries

Cons:

  • Can't include attributes other than href. What if I want to include title and type for example?
  • Can't have multiple links with the same rel, although i think it is a bad practice to have multiple links with the same relationship anyway.

Facebook Graph API implements this format under connections if you request the API with ?metadata=1.

rel as a key, url as a hash

{
  "id": 1234,
  "name": "Bob",
  "links": {
    "self": { "href": "/people/1234" },
  }
}

Pros:

  • Easy to parse, yet extensible and can include other attributes

Cons:

  • Can't have multiple links with the same rel. Same as above.

GitHub API v3 implementes this format in some of the data types.

links as an array

{
  "id": 1234,
  "name": Bob,
  "links": [
    { "rel": "self", "href": "/people/1234" }
  ]
}

Pros:

  • Extensible and straightforward.

Cons:

  • A little bit annoying to parse, although it could be still one-line grep or select in most languages, and you can write a wrapper anyway.

Ruby gem roar implements this format.

@steveklabnik
Copy link

You need to define a media type. Using JSON's serialization semantics is totally fine, but you can't define links inside of application/json.

For two examples of hypermedia-enabled JSON, see HAL and Collection+JSON.

@miyagawa
Copy link
Author

@jshirley yes, I tried Ruby's roar gem (mentioned in the original post) and it does basically the same thing.

@miyagawa
Copy link
Author

@steveklabnik I don't think defining a media type is mandatory. In fact one of the trends I observe is to provide one resource endpoint and let clients negotiate the media type using the Accept header.

@miyagawa
Copy link
Author

@steveklabnik Thanks for the links to HAL and Collection+JSON. Quick glance shows that HAL uses #2 format (same as github's API)

@steveklabnik
Copy link

I mean that you, as the producer of your API should be. Accept headers are how clients request a specific type they have knowledge of.

What you're doing here is defining a media type; extra semantics on top of something. application/json has no link semantics, so as soon as you say "We're serving application/json, but we're adding a 'links' element to each response", you've created a new media type, just given it no name for a client to Accept against!

This is why Fielding says A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

If you don't formalize and document the media type, the fact that you have a 'links' section is out-of-band knowledge, and breaks the 'self-descriptive messages' sub-constraint of the uniform interface constraint.

@miyagawa
Copy link
Author

Oh, sorry I thought you meant that you should add MIME-type as a type attribute to each of the links in the body. Yeah, I guess you should be able to represent this entire JSON format in something other than application/json like application/vnd.mycompany.blahblah or something like Collection+JSON.

@steveklabnik
Copy link

Ahhh yeah, I'm not a favor of adding type information to the link.

I would exactly make it application/vnd.mycompany.blahblah+json. :)

@steveklabnik
Copy link

... the important thing to remember is that whichever of these things you choose, it's no longer application/json any longer. Which is totally fine, and actually, better, even.

@steveklabnik
Copy link

Oh, and last thing, since I didn't actually weigh in on which format: I actually like the ROAR or GitHub ones the best. :)

@steveklabnik
Copy link

I'll just leave this here: https://gist.github.com/794419

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment