Hypermedia API Link Traversal & Practicality

757 Views Asked by At

I've been trying to build a hypermedia based API. Things seem working well. Say when I fetch /books/isbn/12313441213 I get something like this:

<book>
  <id>123</id>
  <name>Hypermedia APIs</name>
  <description>Basic api design techniques</description>
  <tags>
    <tag>rest</tag>
    <tag>api</tag>
    <tag>service</tag>
  </tags>
  <authors>
    <link rel="author" uri="/authors/id/22" />
    <link rel="author" uri="/authors/id/18" />
  </authors>
</book>

Now I can traverse the authors from this resource. When I fetch /books/by/author/id/18 I get something like this:

<books>
  <book id="123">
    <name>Hypermedia APIs</name>
    <link rel="self" uri="/books/id/123" />
  </book>
  <book id="191">
    <name>Chef Recipes for Rails Developers</name>
    <link rel="self" uri="/books/id/191" />
  </book>
  <book id="220">
    <name>Rails 4 Cookbook</name>
    <link rel="self" uri="/books/id/220" />
  </book>
  <book id="292">
    <name>Ruby 102</name>
    <link rel="self" uri="/books/id/292" />
  </book>
  <book id="432">
    <name>Semantic Architecture</name>
    <link rel="self" uri="/books/id/432" />
  </book>
  <book id="501">
    <name>Service Oriented Design</name>
    <link rel="self" uri="/books/id/501" />
  </book>
</books>

Which also seems to be working fine for me. Whether or not this way of uri templating is good, my question is around how practical to traverse links like this?

Considering you want the resource in full-depth (including author details), you have to make at least 3 calls to the server. Again for the collection, you have to make tons of calls to the server. Yes maybe I could utilize resource expansion here, but then why would I use hypermedia links at all since all of my clients will be using expanded resources in time.

I understand we are gaining lots by letting clients to traverse links (ie. if clients build relation based resource discovery, they will be impacted minimum when we change the api, or they are forced to get the most recent schema from the resource endpoint itself, etc). Then again, practicality of this approach, or the performance of this approach would kill the system.

Either I'm not getting something in hypermedia api design, or hypermedia api sounds great but it seems it's just a theoretical idea, not a practical one.

Any thoughts on this?

2

There are 2 best solutions below

1
On

It would be more traditional to use parameters:

GET /books?author=18

I would expect that the response would look more like:

Hypermedia APIs

You can also use a parameter to indicate what fields on sub-resources you want visible. Something like

GET /books/18?expand=author(name, birthday)

which would return the author's name and birthday as part of the author tag in the response. Then you can provide a reasonable default for how much author information users get when they ask for a book (maybe just the author's self and name), but they can get more details if they want by altering the parameter.

Those kinds of customization can help cut down on the number of calls that need to be made.

Another observation is that a lot of this data can be cached, either on the client or on intermediate proxies. It's not likely that much will change about a book or an author, so those resources can let the client cache them for a long period of time. Then there's no round trip at all - the client hits their own local cache for the data.

3
On

This is a great question of all the time. In fact, another big question is: who knows the traversal rels to reach a particular resource R?

For example to reach to "book-detail" resource the client have to make a call to the entry of your api eg "/" then using the rel "book-categories" get uri to book-categories then make a call to OPTIONS to see if GET operation is possible on that resource then do get the book categories, then get the rel to "books-in-category" resource ...etc which ultimately goes to "book-detail" resource. That traversal path to resource R should be part of the knowledge of the client. But don't hard-code the urls, just read the urls at run time. This is considering machine-to-human scenario. The inefficiency is still there. In the case of machine-to-machine scenario, an automaton that starts from "/" can go through your API and do certain processing to your resources. If the automaton has to reach to all resources in the tree (or may be state machine) then there is no inefficiency. But if the automaton needs to make a call to a resource down in the tree, and it knows only the entry point of the API then it will run in to the issue of making several calls to reach it's point.

Many people will tell you to introduce caching using etags and/or memcached, but caching is to augment performance, you cannot depend on caches 100% because caches get stale, so in those cases the code for traversing resources R1 to Rn should be in your client.

check my question on: https://stackoverflow.com/questions/15214526/why-hypermedia-api

But to answer your question on practicality: if you have a business work flow in which the client is required to go to resource R1 then R2 then ... Rn and you want to enforce that flow, hypermedia is practical. I'm assuming that there are no direct calls to Resource Rx with out going through R1 -> R2 ->... Rx-1.