65

Lately I've been reading about Hypermedia as the Engine of Application State (HATEOAS), the constraint that is claimed to make a web API "truly RESTful". It boils down to basically including links with every response to the possible transitions you can make from the current state.

Let me illustrate what HATEOAS is based on my understanding - and please do correct me if I missed something.

/
    GET: {
        "_links": {
            "child": [
                { "href": "http://myapi.com/articles", "title": "articles" }
            ]
        }
    }

/articles?contains=HATEOAS
    GET: {
        "_items": [
            { "uri": "http://myapi.com/articles/0", "title": "Why Should I Care About HATEOAS?" },
            { "uri": "http://myapi.com/articles/1", "title": "HATEOAS: Problem or Solution?" }
        ],
        "_links": {
            "self": { "href": "http://myapi.com/articles", "title": "articles" },
            "parent": { "href": "http://myapi.com/", "title": "home" }
        }
    }

    POST: {
        "title": "A New Article",
        "body": "Article body",
        "tags": [ "tag1", "tag2" ]
    }

/articles/0
    GET: {
        "title": "Why Should I Care About HATEOAS?",
        "body": "Blah blah blah"
        "tags": [ "REST", "HATEOAS" ],
        "_links": {
            "self": { "href": "http://myapi.com/articles/0", "title": "article" },
            "parent": { "href": "http://myapi.com/articles", "title": "articles" }
        }
    }

HATEOAS is claimed to provide two major benefits:

  1. The entire service is discoverable starting form the root URI, documentation is no longer needed.

  2. The client is decoupled from the server which can now change the URI structure freely. This eliminates the need for API versioning.

But in my view, a service is a lot more than its URI structure. To use it effectively, you also need to know:

  • what query parameters you can use and their possible values
  • the structure of the JSON/XML/whatever documents you need to send in your POST/PATCH/etc requests
  • the structure of the response sent by the server
  • the possible errors that might occur
  • ...

Based on the above, HATEOAS only solves a tiny fraction of the discoverability and coupling problems. You still need to document the above four aspects and clients will still be strongly coupled to the server because of them. To avoid breaking clients, you still need to version your API.

The only benefit it provides is that you can change your URL structure more or less freely (by the way, what happened to the principle "Cool URIs don't change"?). Is my understanding correct?

0

5 Answers 5

50

I think your instincts are largely correct; those proclaimed benefits really aren't all that great, as for any non-trivial web application the clients are going to have to care about the semantics of what they're doing as well as the syntax.

But that doesn't mean that you shouldn't make your application follow the principles of HATEOAS!

What does HATEOAS really mean? It means structuring your application so that it is in principle like a web site, and that all operations that you might want to do can be discovered without having to download some complex schema. (Sophisticated WSDL schemas can cover everything, but by the time they do, they've exceeded the ability of virtually every programmer to ever understand, let alone write! You can view HATEOAS as a reaction against such complexity.)

HATEOAS does not just mean rich links. It means using the HTTP standard's error mechanisms to indicate more exactly what went wrong; you don't have to just respond with “waaah! no” and can instead provide a document describing what was actually wrong and what the client might do about it. It also means supporting things like OPTIONS requests (the standard way of allowing clients to find out what HTTP methods they can use) and content type negotiation so that the format of the response can be adapted to a form that clients can handle. It means putting in explanatory text (or, more likely, links to it) so that clients can look up how to use the system in non-trivial cases if they don't know; the explanatory text might be human readable or it might be machine readable (and can be as complex as you want). Finally, it means that clients do not synthesise links (except for query parameters); clients will only use a link if you told it to them.

You have to think about having the site browsed by a user (who can read JSON or XML instead of HTML, so a little weird) with a great memory for links and an encyclopædic knowledge of the HTTP standards, but otherwise no knowledge of what to do.

And of course, you can use content type negotiation to serve up an HTML(5)/JS client that will let them use your application, if that's what their browser is prepared to accept. After all, if your RESTful API is any good, that should be “trivial” to implement on top of it?

0
7

The things is, HATEOAS must come with a second pillar that define what a RESTful API is : standardized media type. Roy fielding himself said

A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources".

With a standardized media type that define the transition explicitely, and hypertext to point resource to each other, you can create a resource graph that can take any form without breaking any client. Like the web work, really: you have link between document, and document are written in HTML that define how to follow those links. <a href> is a GET, <form> is GET or POST (and define the url template to use in case of GET), <link type="text/css"> is GET... etc. This is how browsers can navigate arbitrary structured HTML page and the Web.

All the point you made

  • what query parameters you can use and their possible values
  • the structure of the JSON/XML/whatever documents you need to send in your POST/PATCH/etc requests
  • the structure of the response sent by the server
  • the possible errors that might occur

Are points that should be adressed by the definition of you standardized media type. Of course, this is much harder, and not something that most people think about when they define a "REST" API. You can't just take you business entities and shove their attributes into a JSON document to have a RESTful API.

Of course, what happened is REST got somehow diluted to mean "use HTTP instead of complicated SOAPy thingy". Just using HTTP and HyperText is not enough to be RESTful, this is what most people get wrong.

Not that this is necessary a bad things : REST make sacrifice of performance and ease of development in exchange for longer term maintainability and evolutivity. It was made for big entreprise application integration. A small web API with hard-coded JSON structure may be what you need. Just don't call it REST, its an ad-hoc web API, nothing more. And that don't mean it suck, it just mean it doesn't try to follow the constraint of REST.

Further reading

Hope this help clarify a bit :)

2

There are some Hypermedia formats which endeavour to provide richer responses which include more information about what kind of requests to send, and there's nothing stopping you from enriching the response with even more information.

Here's an example Siren document:

{
  "class": [ "order" ],
  "properties": { 
      "orderNumber": 42, 
      "itemCount": 3,
      "status": "pending"
  },
  "entities": [
    {
      "class": [ "info", "customer" ],
      "rel": [ "http://x.io/rels/customer" ], 
      "properties": { 
        "customerId": "pj123",
        "name": "Peter Joseph"
      },
      "links": [
        { "rel": [ "self" ], "href": "http://api.x.io/customers/pj123" }
      ]
    }
  ],
  "actions": [
    {
      "name": "add-item",
      "title": "Add Item",
      "method": "POST",
      "href": "http://api.x.io/orders/42/items",
      "type": "application/x-www-form-urlencoded",
      "fields": [
        { "name": "orderNumber", "type": "hidden", "value": "42" },
        { "name": "productCode", "type": "text" },
        { "name": "quantity", "type": "number" }
      ]
    }
  ],
  "links": [
    { "rel": [ "self" ], "href": "http://api.x.io/orders/42" },
    { "rel": [ "previous" ], "href": "http://api.x.io/orders/41" },
    { "rel": [ "next" ], "href": "http://api.x.io/orders/43" }
  ]
}

As you can see, information about how to call related actions is provided in the message, and then by interpreting this information, the client becomes more resistant to change.

It becomes particularly powerful if rels are URIs which can be looked up, rather than from a fixed vocabulary.

1

(HATEOAS), the constraint that is claimed to make a web API "truly RESTful"

The only thing that makes it a true REST API is meeting all the constraints, not just a single one.

But in my view, a service is a lot more than its URI structure. To use it effectively, you also need to know: ...

That's why we need the other constraints, self-descriptive message, etc...

To avoid breaking clients, you still need to version your API.

No matter how you try you'll need to version your API. In a REST client you still need to know how to get to a page where you want to do stuff, which links to follow and which properties you need to collect based on the RDF vocab describing the message. If you need to replace or remove something from that vocab, then it will probably break all your clients and you'll need a new version. So I think REST is not something you should publish early (and figure out the model while you are constantly changing the API), otherwise you'll have many versions. You need a stable domain model first you can build on...

0

Where did you read that "documentation is no longer needed" for HATEAOS services? As you say, you still need to document the semantics of the links. However, with HATEOAS you don't need to document, and hence keep forever, the structure of most of the URIs.

HATEOAS allows a service implementer to modify and scale the implementation significantly and efficiently without changing a small set of URIs on which the client depends. It is easier to keep a small number of entry points unchanged than a large set. Hence, reducing the number of public entry points to the service and dynamically providing links to sub-resources (HATEOAS) actually supports "Cool URIs don't change" better than non-HATEOAS services.

2
  • One place where one can read that "documentation is no longer needed" is the dissertation of Roy Fielding, who coined the term.
    – meriton
    Jun 5, 2015 at 18:54
  • 1
    I just searched Fielding's dissertation for uses of "documentation" and found nothing resembling the statement "documentation is no longer needed". Can you please indicate where in Fielding's dissertation you found this claim? Jul 13, 2015 at 8:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.