Hi! My name is Evert, and for a while now I've been working on a project called Ketting, which is a generic Hypermedia/HATEOAS client for Javascript. I just released version 5.0, and thought it might be interesting to share the new features that have been added since earlier this year.

These are the highlights.

Support For Siren

Ketting now features support for Siren. This means that the client now understands this format and can transparently traverse Siren links.

const newRes = await res
  .follow('author') // this could be a HTML5 link
  .follow('me') // This might be a Siren link 

Ketting now has support for HTML, HAL, JSON:API, HTTP Link headers and Siren links. Collection+JSON is also in the works and will likely follow soon after in a point release.

Advanced Follow Features

Usually if you want to fetch a collection of things, you might do it using this API:

const articles = await res
  .follow('article-collection')
  .followAll('item') // This might be a list of links to each individual article

In HTTP/1.1 style APIs, it was common to actually embed the responses of every 'item' in a collection using for example's HAL _embedded property or JSON:API's included.

This is kind of an anti-pattern, but a necessary evil because HTTP/1.1 requests have a large amount of overhead.

Ketting will take all the items in _embedded and store the items in its cache, so that future GET requests are not needed.

In HTTP/2 APIs requests are less expensive, and it's often desirable to make more smaller HTTP requests and responses.

To help with this, the follow/followAll have these new features:

Prefetching

const newRes = await res
  .follow('article-collection')
  .followAll('item')
  .preFetch();

The preFetch() on followAll will cause Ketting to follow every item link, do a GET request for each in parallel in the background and store it in its cache.

We did some testing with an internal application and were able to prefetch an entire collection of 1700 items (so 1700 GET requests) in about 7 seconds.

While this could benefit from some paging, it was great to see how fast HTTP/2 servers can be.

Sending Prefer-Push

Very similarly, there's also a chainable preferPush() on follow / followAll:

const newRes = await res
  .follow('article-collection')
  .followAll('item')
  .preferPush();

This will cause Ketting to send a Prefer-Push header when fetching the articles collection:

GET /articles HTTP/2
Prefer-Push: item

If a server supports this header, they can optimize future requests by sending HTTP/2 pushes for each linked item.

Support For rel="invalidates"

Ketting now understands the 'invalidates' link relationship from draft-nottingham-linked-cache-inv.

A use-case for this is that a client might do a POST request on some resource, and the result of this resource causes other cached responds to invalidate.

This is handy, because an operation on one resource can alter the state of other, unrelated resources. Using this HTTP header, a server can tell a client which resources those are and control invalidation.

New OAuth2 Library

Older versions relied on the client-oauth2 for everything OAuth2, but this library is pretty bulky when WebPacked. This has since been changed over to fetch-mw-oauth2, which is a library that wraps fetch() as a middleware and decorates it with OAuth2 features.

This caused the final Ketting Webpack distribution to drop over 30KB. While making this change, support for OAuth2 authorization_code was also added.

Per-Domain Authentication

One of the nice advantages of using a hypermedia-style API, is that if multiple APIs support links, one way to integrate these APIs is simply by pointing links from one API to another.

A real life example was that one of our APIs needed some integration with the Github REST api, which uses HTTP Link headers for some stuff.

Our API could simply point to Github endpoints and the client was able to just traverse the graph and didn't have to be aware that some endpoints were served by Github.

However, our API and Github's each have their own authentication mechanisms. In previous Ketting versions authentication could only be set up once globally, causing the same credentials to be sent everywhere.

With the new authentication layer, it's possible to set Ketting up to use different authentication mechanisms based on the specific domains you're accessing, including wildcards.

const ketting = new Ketting(bookmark, {
  match: {
    '*.github.com': {
       auth: {type: 'oauth2', /*...*/ }
    },
    'api.example': {
       auth: {type: 'basic', /*...*/ }
    },
  }
});

Typescript Improvements

It's now possible to add Typescript annotations to various Ketting methods.

Consider the following example

type Article = {
  title: string,
  body: string
};

const itemRes = await res1.follow<Article>('item');

This tells Typescript that the result of this follow() function is actually a Resource<Article>.

If a user later calls:

const body = await itemRes.get();

body will now automatically have the Article type. Similarly, item.put() will also now require a parameter of type Article.

There's many more examples of this, which you can read on my previous post on this subject.

201 And 205 Responses On POST

If a user calls .post() and the response to the HTTP POST request was a 201 Created and a Location header, it would automatically return a new resource.

const newArticle = await articlesCollection.post(newArticle);

Now, when a server returns a HTTP 205 Reset Content, the post() function will return the resource itself (this).

This is a small change that I hope is useful for APIs with strong hypermedia controls and folks that want to create clients that heavily rely on the entire application state being managed by the server.

Conclusion

I hope you like the changes. My goal is to create the ultimate client for Hypermedia APIs, and I feel these are some good steps in that direction.

If you're an existing user, I would be very curious to hear what's currently painful and help adjust the future of this project.

If you're a new user and interested in using it, check out the Github project and documentation (The latter of which also got a big overhaul).