简体   繁体   中英

Runtime discovery of HATEOAS hypermedia?

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?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM