38

As I currently understand HATEOAS is basically all about sending together with each response links with information about what to do next. One simple example is easily found on the internet: a banking system together with an account resource. The example shows this response after a GET request to an account resource

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">100.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
    <link rel="withdraw" href="/account/12345/withdraw" /> 
    <link rel="transfer" href="/account/12345/transfer" /> 
    <link rel="close" href="/account/12345/close" /> 
</account>

Together with the data there are links telling what can be done next. If the balance is negative we have

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">-25.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
</account>

So that we can only deposit. That's all fine, if we are using Fiddler or making requests with the browser we can easily see what can be done. This kind of information is useful then for us to discover the API's capabilities and the server is decoupled from the client.

The point, however, is that when we build a client, like a SPA with Javascript, or an Android app or many other things, I can't see how HATEOAS continues being relevant. What I mean is the following: when I'm coding the SPA in javascript, I must know what can be done in the API in order to write the code.

So I need to know the resources, the methods supported, what they expect to receive and what they give back in order to write the ajax calls to the server and even in order to build the UI. When I build the UI, I must know that after requesting the account, one can for example deposit into it, or I won't be able to provide this option on the UI. Also, I'll need to know the URI to make the deposit to build the ajax call.

What I mean is, when we make requests to the API, links do allows us to discover and use the API better, but when we build a client, the app we are building won't simply look at the links and then by itself render the correct UI and make the right ajax calls.

So, how is HATEOAS important for the clients? Why do we bother with HATEOAS anyway?

user1620696
  • 4,817
  • 7
  • 31
  • 46
  • 1
    You're right, but that's not the point. HATEOAS keeps you from having to construct the URIs for the links in the page on the client. – James McLeod Feb 08 '15 at 23:00

3 Answers3

25

the app we are building won't simply look at the links and then by itself render the correct UI and make the right ajax calls

In fact, this is exactly what HATEOAS will give the UI. Not what is possible, but when it is possible. A formal HATEOAS like HAL, as the question states, gives links that indicate what is possible. But when those links show up depends on the state of the application. So, the links can change on the resource over time (based on actions that have already been performed).

This allows us to build a UI that contains all the possible states, but not be concerned with when those states become active. For example, the presence of the rel="deposit" can directly tell the UI when it is OK to render the make deposit form. Which then allows the user to enter a value and submit using the link.

Davin Tryon
  • 1,235
  • 1
  • 10
  • 15
  • 2
    So when building the UI we still need to know everything that the API offers, and then looking at those links we are able to know the state the information on the server is at? So for instance, the UI knows it's possible to deposit, withdraw, transfer or close (knows the possible rels), then it checks what came back in order to see the state? – user1620696 Feb 09 '15 at 22:12
  • 1
    Yes, it could. Again it depends on how dynamic that you want to take it. As others have mentioned, the ability to change links on the server (and not break clients) is another advantage. And this becomes very interesting once your API has an iPhone, Android, Windows Phone, Mobile Web and Web clients that all use it (not to mention if your API is published for others to build clients on). – Davin Tryon Feb 09 '15 at 22:16
  • @user1620696 You should know all of this anyway through both the client and server understating the content type if the resoure. Content type is a lot more than dumb xml or Json. You should have some "bank deposit" content type that the client understand how to work with – Cormac Mulhall Feb 10 '15 at 13:23
  • This only applies when the app that uses the API acts like a browser. – Jimmy T. Jan 15 '18 at 11:50
  • @DavinTryon "As others have mentioned, the ability to change links on the server (and not break clients) is another advantage." -- this is a huge advantage! Could you please give an example of how such a client can be implemented "on top of" dynamic HATEOAS links. – Myk Jan 25 '19 at 11:03
  • 1
    @Nik take a look at [HAL](https://apigility.org/documentation/api-primer/halprimer) for an example of how the links are provided in the response. – Davin Tryon Jan 25 '19 at 11:11
  • @DavinTryon Thanks for the response. So, for example, given this link `"first": { "href": "http://example.com/api/book/catalog" }` 1) if `href`'s value changes, the existing [properly designed] clients keep working but 2) if the link's name changes from `first` to `begin`, it will break the existing clients. Would you say my understanding is correct? – Myk Jan 25 '19 at 11:32
  • 1
    yes, you still have backwards compatibility concerns. This can be solved by including a version header or version in the url. But, I would say you are understanding correctly. – Davin Tryon Jan 25 '19 at 11:53
3

As I currently understand HATEOAS is basically all about sending together with each response links with information about what to do next

HATEOAS is a lot more than just links. It is "hyper media" as the engine of application state.

What is missed in your description is the content type, the formal definition of the hyper media that is passed between client and server.

HTML is an example of hyper media, and an example of why HATEOS works. The HTML page itself is the engine that allows the client (ie the user) to move through the site. A browser with just an ability to render HTML present to the user a fully navigable website. It is not simply that it passes links to the other pages but it passes them in a meaningful way that gives context to the links and in a fashion that allows the browser to construct a navigable site.

And most importantly the browser can do this with ZERO up front understanding of the website itself. The browser only knows HTTP and HTML. Based on that simple understanding it can present the New York Times to the user to navigate through.

This holds even if the "user" is another computer program. The hyper media itself should define the context of navigation.

Cormac Mulhall
  • 5,032
  • 2
  • 19
  • 19
  • 1
    Wouldn't this mean that you must build a client as complex (and bug prone) as a browser? Flexibility often comes with complexity as a cost... – Andres F. Feb 09 '15 at 12:33
  • @AndresF. it doesn't mean that you *must* or *should* do so, it merely gives you the option to do it dynamically if you want or need it. – Peteris Feb 09 '15 at 15:25
  • The complexity of the client will depend on the content type. I would not recommend building a content type as complex and error prone as HTML :-) – Cormac Mulhall Feb 09 '15 at 15:29
  • What type of "another computer program" really can surf this hypermedia by itself without a live human? A crawler maybe.. But the real client (Android app, JS app etc) don't really get any benefits. For HTML and browser the benefits is clear - the human surf it. If the point of HATEOAS is to make an API to be human-surfable, then yes, I understand the benefits. But oftern it is advertised as something that makes your API surfable by non-human. What kind of non-human-program they refer to? An API crawler? I can't imagine nothing else. – Ruslan Stelmachenko Dec 17 '17 at 16:52
  • The "real client" doesn't benefit from this if you don't write the client to do this, obviously. But then that is true of anything, a client won't understand any API, RESTful or otherwise, if you don't give it the logic to navigate the API. The point with REST is that logic should exist in the content type, rather than hard coding URL endpoints into the client. – Cormac Mulhall Dec 18 '17 at 15:20
  • @CormacMulhall "The "real client" doesn't benefit from this if you don't write the client to do this" -- Could you please give an example of writing a client capable of benefiting from the HATEOAS links, short of embedding a general AI engine in this client. – Myk Jan 25 '19 at 10:58
  • 2
    @nik Sure. Off the top of my head imagine that you have a service providing ancestry information via restful api. You have a content type that defines the format of a 'Person' resource that has various information about them but also defines what relationships look like, say 'brother' or 'sister' or 'mother' etc. Because this is hypermedia those relationships simply have a URI to another Person resource. A fairly simple client using the HTTP verbs and understanding this 'Person' content type can navigate through this API. Say you want to find all direct descendants of a particular person. – Cormac Mulhall Feb 06 '19 at 16:44
  • 2
    @nik This client needs to understand simply the content type of the resource it has accessed and HTTP verbs (GET, PUT, DELETE etc) and you can navigate through this API fetching and updating resources. And, more importantly, any client that understands the content type can jump, via a URI, to another server entirely and continue on as they were. They don't care what server they are talking to, they care only about the content type of the resource, do they understand it or not. – Cormac Mulhall Feb 06 '19 at 16:48
  • @CormacMulhall thank you for the response! Just to check my understanding, let's imagine the client v1 and the service v1 have the relation types "mother", "father", "brother" "sister". Now the service v2 introduces relation types "aunt" and "uncle". In this case, a client of version v1 is not going to "magically" get aware of the new relation types, correct? – Myk Feb 08 '19 at 14:14
  • 1
    @Nik So in such a situation you have a server that understands the original content type (say Person v1) and the new content type (Person v2). The client only understands Person v1. The client tells the server what content types it understands via the Accept header in HTTP. Using content negotiation the server determines if it will send what the client supports, in which case it will return the resource using content type Person v1. Now you may want to simply stop supporting this old content type and can send the client a 406 error. It is better to try and support as much as you can though. – Cormac Mulhall Feb 11 '19 at 11:06
  • Just to be clear though, in the example of a browser, the content type "HTML" is all the browser needs to understand to render the entirety of a page. It's a little deceiving to make it sound like a client application accessing a server API that implements HATEAOS is this dynamic. The "content type" in this situation is much more specific, e.g. a Person. The reality is the client application needs to know the exact structure of every resource, which is still a lot of coupling between server and client. – wired_in Apr 06 '21 at 19:10
  • So again, saying the client "only needs to understand the content type" is a little deceiving when comparing it to how a browser only needs to understand HTML. HATEOAS is most useful as the driver of state, with the added benefit that you don't have to hard code the URLs on the client. – wired_in Apr 06 '21 at 19:12
  • It is, and this depends on how semantic the resources are. But this is inevitable, the more specialised the domain the client has to understand the more specialised the content types will be – Cormac Mulhall Apr 08 '21 at 10:26
2

You don't have to build a dynamically generated interface. Though it could be nice it's not required. If you cannot build a dynamic interface just use the links and you are done. Disadvantage is that you are again hard linked to the backend and will crash if something changes.

Using the dynamic layout can be quite simple btw:

links.forEach(function(link) {

  switch(link.rel) {

    case 'deposit':
      showDepositButton();
      break;

    case 'withdraw':
      loadWithdrawForm(link.href);
      showWithdrawButton();
      break;
  }

});

It saves you in your client code like:

if (balance <= 0 && negativeBalanceAllowed === false) {
  showWithdrawButton();
}

You can implement an allowed negative position (by borrowing money for example) without changing your client.

Nicholas Shanks
  • 337
  • 2
  • 12
Luc Franken
  • 2,664
  • 15
  • 9
  • As a slightly stronger example, the bank can offer variable overdraft limits on their accounts, without having to tell the client side what the limit is on each account. – Bart van Ingen Schenau Feb 09 '15 at 09:30
  • Correct you can make the decision of balance limits as complex as you want and still don't have to make changes to the client. If you take this further with REST parts like content type you can show different views. For example an account looks different from a transaction. Also interesting is code on demand (though not much implemented). That could be used for example for a borrowing estimator. It can give the interface a simple calculator function so the client only needs to implement the inputs for the calculation. It will stay up-to-date from the back-end. – Luc Franken Feb 09 '15 at 13:38
  • 4
    But usually the customer need to know WHY it can't withdraw, so we still need to send an ENUM or String in separate field to the client with `reason`. And if we still need this, why not simply send him another boolean field `canWithdraw` instead of a link to the action? Another advantage is ability to change an action's URL without touching the client. But.. what reason to change the URL? In most cases it also some change in semantic or parameters or request/response shape etc. So we anyway need to change the client. So, I still don't get it - what the point of HATEOAS. – Ruslan Stelmachenko Dec 17 '17 at 16:41