11436 SSO

How to Improve your APIs with Hyperlinks

mnally
Aug 18, 2015

If you follow discussions about API design, you will know that the topic of hyperlinks draws a lot of controversy. There are certainly aspects of the use of hyperlinks that are worthy of debate, but we think that adding basic hyperlinks to an existing API, or designing them into a new one from the start, is a simple thing to do and makes the API much easier for users.

Here is an example of a simple API that doesn't have hyperlinks. Most of you will be familiar with the style of API this example illustrates. Here is what a "Dog" resource looks like:

{ "id": "12345678",

 "type": "Dog"

 "name": "Lassie",

 "fur_color": "brown",

 "owner": "98765432"

}

This is what a "Person" resource looks like:

{ "id":"98765432",

 "type": "Person"

 "name": "Joe Carraclough",

 "hair_color": "brown"

}

The documentation tells us that the API exposes these URLs and URL templates, and tells us how to use them:

http://example.org/persons

http://example.org/persons/{person_id}

http://example.org/persons/{person_id}/dogs

http://example.org/dogs

http://example.org/dogs/{dog_id}

With this knowledge, we can navigate the API, including updating resources and creating new ones.

Enhancement with hyperlinks

The simplest way to enhance this API with hyperlinks is to add these two highlighted lines:

{ "id": "12345678",

 "type": "Dog"

 "name": "Lassie",

 "fur_color": "brown",

 "owner": "98765432",

 "ownerLink": "http://example.org/persons/98765432"

}

and

{ "id":"98765432",

 "type": "Person"

 "name": "Joe Carraclough",

 "hair_color": "brown",

 "dogs": "http://example.org/persons/98765432/dogs"

}

Why is this better?

In the original example, if you had in your hand (or in your client application) the representation of Lassie, and you wanted to get the representation of Lassie's owner, Joe, you would have to look in the API documentation to find a suitable URL template you could use to construct a URL that can be used to locate Joe. In the representation of Lassie, you have an “owner” property, so you're looking for a URL template that takes an “owner” as a variable and produces a URL that locates an owner.

This has several drawbacks. It requires you to go hunting in the documentation. There also isn't really a good documentation convention for describing which property values can be plugged into which templates, so some amount of guesswork is usually necessary, even given the right documentation.

In this example, you would have to know that owners are people, and look for templates that take the ID of a person as a variable. A third drawback: you have to write code that will combine the “owner” property value with the template and produce a URL—the template specification calls such code a 'template processor'. For simple templates, this code is very simple, but it still has to be written and debugged.

In our enhanced design, there is less to learn, and using the API is easier. Joe's URL is right there in the data for you to see, so you don't have to go hunting for anything in documentation, and your client code simply has to pick up the value of "ownerLink" and use it—you do not have to write code to construct it.

Essentially, the server just did what the client would otherwise have had to do—it figured out the relevant URL templates, and which property values could be plugged into them as variables, and it did the variable substitution and provided the results to the client in simple JSON properties.

Note that we have taken nothing away—clients can continue to navigate using the URL templates as before, allowing them to “skip” to resources not anticipated by the server in hyperlinks.

One step better still

Let's add a new resource whose URL is http://example.org:

{"type": DogTracker",

"dogs": "http://example.org/dogs",

"persons": "http://example.org/persons"

}

Here's what http://example.org/dogs looks like. It hasn't changed from the original, with the exception of the addition of the highlighted line, which you have already seen:

{"type": "Collection",

"items: [

    {"id": "12345678",

    "type": "Dog"

    "name": "Lassie",

    "fur_color": "brown",

    "owner": "98765432",

"ownerLink": "http://example.org/persons/98765432"

    },

    … other dogs here …

  ]

}

http://example.org/persons/98765432/dogs is similar, and

http://example.org/persons follows the same pattern.

Why is this better?

At this point, our API is fully connected. If I have a suitable browser or browser plugin, I can point it at http://example.org and browse through the entire API without having to look in the documentation and without any special tools or metadata descriptions. How cool is that?

Summary page photo: Hide/Flickr

Microservices Done Right

Next Steps

 
 

Resources Gallery

News