1

I understand HATEOAS represents the applications state by sending all actions that can be performed at that point in time within the application as it's response (HAL, JSON-LD, etc).

For example, viewing an account resource of a bank may allow you to deposit, withdraw or close the account (OPTIONS which may return UPDATE and DELETE verbs).

In terms of runtime discoverability of these links (by the consuming client), how might one go about this?

If the purpose of sending these links is the decouple the client from the server and drive the state by the hypermedia in the response, there must be an amount of knowledge the developer must hardcode in the application in order to make any sense of the responses being returned.

I understanding sending OPTIONS requests is the way to determine the current state of the resource and what you can do next, but in order to discover the actual URIs to use - would these simply be hardcoded as COOL URIs?

Jacob Clark
  • 3,317
  • 5
  • 32
  • 61

2 Answers2

2

Like @VoicesOfUnreason said, in HATEOAS URIs are discoverable (and not documented) so that they can be changed. That is, unless they are the very entry points into your system (Cool URIs, the only ones that can be hard-coded by clients) - and you shouldn't have too many of those if you want the ability to evolve the rest of your system's URI structure in the future. This is in fact one of the most useful features of REST.

For the remaining non-Cool URIs, they can be changed over time, and your API documentation should spell out the fact that they should be discovered at runtime through hypermedia traversal.

Looking at the Richardson's Maturity Model (level 3), this would be where links come into play. For example, from the top level, say /api/version(/1), you would discover there's a link to the groups. Here's how this could look in a tool like HAL Browser:

Root:

{
  "_links": {
    "self": {
      "href": "/api/root"
    },
    "api:group-add": {
      "href": "http://apiname:port/api/group"
    },
    "api:group-search": {
      "href": "http://apiname:port/api/group?pageNumber={pageNumber}&pageSize={pageSize}&sort={sort}"
    },
    "api:group-by-id": {
      "href": "http://apiname:port/api/group/id" (OR "href": "http://apiname:port/api/group?id={id}")
    }
  }
}

The add would simply be a POST to that endpoint, and then you'd have 2 GET methods.

GET /api/group?pageNumber=0&pageSize=20&sort=asc

which could return something like this:

{
    "groups": [
      {
        "id": 123,
        "name": "Test Group"
      }, 
      {
        "id": 134,
        "name": "Tennis squad"
      }
    ]
}

Then once you drill down to a particular group (say #123):

{
  "Id" : 123,
  "Name" : "test",
  "_links": {
    "self": {
      "href": "/api/group/1" (OR "/api/group?id=1")
    },
    "edit": {
      "href": "http://apiname:port/api/group/1"
    },
    "api:delete": {
      "href": "http://apiname:port/api/group/1"
    },
    "api:items-query": {
      "href": "http://apiname:port/api/bonus?groupId=1"
    }
  }
}

Here, the edit would simply be a PUT, and then you'll need a DELETE (see level 2 of REST in that same link), as for the items, you probably know best if they are just a property, or another endpoint; you could even embed them to be returned in the same call that's retrieving a group.

The advantage here would be that the client would only need to know the relationship (link) name (well obviously besides the resource structure/properties), while the server would be mostly free to alter the relationship (and resource) url.

Alexandru Marculescu
  • 5,569
  • 6
  • 34
  • 50
  • Thanks for this, in terms of hypermmedia traversal, what techniques would you use to do this? Can you provide any code samples, libraries or frameworks? – Jacob Clark Sep 13 '16 at 07:31
  • @JacobClark I've edited my answer to drill down a bit on some details – Alexandru Marculescu Sep 13 '16 at 08:47
  • So if I understand you correctly - the case here is the client needs to understand the structure of the resource (aka how to reach the api:delete property) simply in order to retrieve the link, so that in the event of the server changing the url (resource), the client doesn't need to do anything as how it reaches the link has stayed the same. Thus less changes are needed to the client when updating how the relationship between data is modeled. In theory then - if I wanted to change the entire relationship/resource structure, I could do so with very minimal impact to my clients? – Jacob Clark Sep 13 '16 at 15:37
0

There's a bunch of prior art around on trying to create expressive, discoverable hypermedia. You might want to review:

I am thinking maybe a series of if statement that checks for certain properties to determine the state or maybe even switch statements. Is this is correct path - or is there better means of hypermedia discovery?

My current thinking is that you want to be shaping your ideas more along the lines of negotiating and following a protocol; so think state machine rather than if statements.

For starters, review How To GET a Cup of Coffee.

The hyperlinks in the documents served by RESTBucks are designed to assist the client in negotiating the RESTBucks protocol; the assumption that the client already understands that protocol is baked into the model. In other words, the client already understands that negotiating the protocol will allow it to reach it's goal.

Of course, there could be multiple protocols that serve the same goal. For instance RESTBucks could also support a "Give Away Day Old Coffee" protocol; announcing the presence of each, the client would be expected to choose which is the better expression of the goal, and follow that path.

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • So essentially, the client still needs to be coupled to the scheme sent back from the server, as that schema is the protocal? – Jacob Clark Sep 12 '16 at 17:44
  • Ish. The client needs to understand the media type (ie, how to process the bytes) in order to communicate with the server at all (content negotiation can help here). In addition, you have the fact that the client needs to understand the application state -- on other words, how to use the links to advance towards its goal. The server provides links as a representation of the choices that are available to the client; the client doesn't need to recognize all of the links, but it can't make any further progress if it doesn't recognize the links that affords progress. – VoiceOfUnreason Sep 12 '16 at 18:38
  • If in this case the client is simply a Java app calling the service over HTTP, it would be a simple case of programming the Java app to understand what to do with each link at each stage of the resources state. What I don't then understand is how this is uncoupled at all? The client must be coupled to the scheme at this stage. However I thought using HATEOS meant the server can change its schema at any time without breaking the client. – Jacob Clark Sep 12 '16 at 18:51
  • No , HATEOAS means that the server can change the spelling of the resource identifiers without breaking the client, and it can expose/revoke resources by excluding the links from the hypermedia representations. It also means that your Java app can talk to any server that supports that protocols. But it doesn't mean telepathy. – VoiceOfUnreason Sep 12 '16 at 18:56