Search code examples
apiresthateoas

RESTful API HATEOAS


I've come to the conclusion that building a truly RESTful API, one the uses HATEOAS is next to impossible.

Every content I've come across either fails to illustrate the true power of HATEOAS or simply does not explicitly mentions the inherent pain points with the dynamic nature of HATEOAS.

What I believe HATEOAS is all about:

From my understanding, a truly HATEOAS API should have ALL the information needed to interact with the API, and while that is possible, it is a nightmare to use, especially with different stacks.

For example, consider a collection of resources located at "/books":

{
  "items": [
    {
        "self": "/book/sdgr345",
        "id": "sdgr345",
        "name": "Building a RESTful API - The unspoken truth",
        "author": "Elad Chen ;)",
        "published": 1607606637049000
    }
  ],

  // This describes every field needed to create a new book
  // just like HyperText Markup Language (i.e. HTML) rendered on the server does with forms
  "create-form": {
    "href": "/books",
    "method": "POST",
    "rel": ["create-form"],
    "accept": ["application/x-www-form-urlencoded"],
    "fields": [
        { "name": "name", "label": "Name", "type": "text", "max-length": "255", "required": true }
        { "name": "author", "label": "Author", "type": "text", "max-length": "255", "required": true }
        { "name": "author", "label": "Publish Date", "type": "date", "format": "dd/mm/YY", "required": true }
    ]
  }
}

Giving the above response, a client (such as a web app) can use the "create-form" property to render an actual HTML form.

What value do we get from all this work?

The same value we've been getting from HTML for years.

Think about it, this is exactly what hypertext is all about, and what HTML has been designed for.

When a browser hits "www.pizza.com" the browser has no knowledge of the other paths that a user can visit, it does not concatenate strings to produce a link to the order page -> "www.pizza.com/order", it simply renders anchors
and navigates when a user clicks them. This is what allows web developers to change the path from "/order" to "/shut-up-and-take-my-money" without changing any client (browsers).

The above idea is also true for forms, browsers do not guess the parameters needed to order a pizza, they simply render a form and its inputs, and handle its submission.

I have seen too many lines of codes in front-ends and back-ends alike, that build strings
like -> "https://api.com" + "/order" - You don't see browsers do that, right?

The problems with HATEOAS

Giving the above example ("/books" response), in order to create a new book, clients are expected to parse the response in order to leverage the true power of this RESTful API, otherwise, they risk assuming what the names of the fields are, which of them is required, what their expected type is, etc...

Now consider having two clients within your company that are using this API, one for the web (browsers) written in JS, and another for the mobile (say an android app) written in Java. They can be published as SDK's, hopefully making 3 party consumers have an easier integration.

As soon as the API is used by clients outside your control, say a 3rd party developer with an affinity to python, with the purpose of creating a new book.
That developer is REQUIRED to parse such a response, to figure out what the parameters are, their name, the URL to send inputs to, and so on.

In all my years of developing I have yet to come across an API such as the one I have in mind. I have a feeling this type of API is nothing more than a pipe dream, and I was hoping to understand whether my assumptions are correct, and what downfalls it brings before starting the implementation phase.

P.S in case it's not clear, this is exactly what HATEOAS compliant API is all about - when the fields to create a book change clients adapt without breaking.


Solution

  • Implementing a HATEOAS API needs to be done both on the server and on the clients, so this point you make in the comments is very valid indeed:

    changing a resource URI is risky given I don't believe clients actually "navigate" the API

    Besides the World Wide Web, which is the best implementation of HATEOAS, I only know of the SunCloud API on the now decommissioned Project Kenai. Most APIs out there don't quite make use of HATEOAS, but are just a bunch of documented URLs where you can get or submit specific resources (basically, instead of being "hypermedia driven", they are "documentation driven"). With this type of API, clients don't actually navigate the API, they concatenate strings to go at specific endpoints where they know they can find specific resources.

    If you expose a HATEOAS API, developers of any clients can still look at the links you return and may decide to build them on their own 'cause they figure what the API is doing, so then think they can just bypass any other navigation that might be needed and go straight for the URL, because it is always /products/categories/123, until - of course - it isn't anymore.

    A HATEOAS API is more difficult to build and adds complexity to both the server and the clients, so when deciding to build one, the questions are:

    • do you need the flexibility HATEOAS is giving you to justify the extra complexity of the implementation?
    • do you want to make it easier or harder for clients to consume your API?
    • does the knowledge and discipline to make it all work exist on both sides (server developers and clients developers)?

    Most of the times, the answer is no. In addition, many times the questions don't even get asked, instead people end up with the approach that is more familiar because they've seen the sort of APIs people build, have used some, or built some before. Also, many times, a REST API is just stuck in front of a database and doesn't do much but expose data from the database as JSON or XML, so not that much need for navigation there.

    There is no one forcing you to implement HATEOAS in your API, and no one preventing you to do so either. At the end of the day, it's a matter of deciding if you want to expose your API this way or not (another example would be, do you expose your resources as JSON, XML, or let the client chose the content type?).

    In the end, there is always the chance of breaking your clients when you make changes to your API (HATEOAS or no HATEOAS), because you don't control your clients and you can't control how knowledgeable the client developer are, how disciplined, or how good of a work they do in implementing someone else's API.