DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Why HATEOAS is not the witch to burn

Giorgio Sironi user avatar by
Giorgio Sironi
·
Jan. 17, 13 · Interview
Like (1)
Save
Tweet
Share
11.97K Views

Join the DZone community and get the full member experience.

Join For Free

A bit late to the party, but some arguments require thinking and finding yourself in the problem a pattern was extracted from, to be able to judge it correctly.

HATEOAS for dummies

Hypertext As The Engine Of Application State is the model upon which the web works: the state of user agent's interaction with the server over HTTP is defined by the page it's visiting now, and not from some data structure kept inside the client's machine. In this model, a state transition as following a link (or submitting a form) means that usually the URL of the next transition is embedded in the representation of the current resource.

For example, you're visiting this page at some URL on css.dzone.com after having clicked on a Twitter link, or another link on a DZone page; maybe even one on the entry point css.dzone.com.
At the API level, HATEOAS implies that the output of your API calls contains further links to other resources; depending on your accepted formats, these links can be placed inside headers, or in JSON or Atom bodies of the response.

If you build all your APIs following this rule of thumb, this would mean that the /posts resource would contain links to all the /post/1, /post/2. To the pitchforks, this is a useless abstraction!

More seriously: design decisions

I suspect of every design "rule", that is a decision taken in some context and blindly transported into other domains and projects. I firmly believe the form of your software is shaped by its context (talking in Alexandrian terms) and not by gurus building an application with a different (from yours) number of users in a different domain, serving different type of clients and with different maintenance requirements.

When I first heard about HATEOAS and read Mike Amundsen's book Building Hypermedia APIs, I thought: this movement is trying to rebuild web applications, which embed in responses the links to the next resources, but with machines on the client side instead of humans. I've never seen intelligent machines capable of navigating with a browser, so this is doomed to fail.

Then I started to work on applications with complex workflows, where your interaction doesn't stop with a POST and a GET to retrieve the result but goes on for 4, 5 or more different requests; having to support more than one kind of client, including deployed Android devices. And I found myself happy to know including URLs in responses was allowed.

Allocating responsibilities

Design is also about the assignment of responsibilities to the different components of your application; in the case of web applications, we are usually talking at least of two separate nodes, the client and the server. In the case of mobile native applications, a further specialization, the client side may have been deployed months or years ago without the capability to upgrade (users don't push the upgrade button, I'm sorry).

In the face of changing requirements and evolution of the workflow, what can you support with a fixed client? It depends on how your design responds to this.

For example, recently I was working on the entry point of an API, which we'll call /widgets. When executing a POST to /widgets, the user should go to the page of the newly created widget, and it is sent there with a Location header containing the full URL:

HTTP/1.1 201 Accepted
Location: http://www.example.com/widgets/42

This is an HATEOAS design: you're not relying on knowing more URLs than the initial URL to navigate through. In this case, the advantage is clear as the client doesn't know the :id in the /widgets/:id that he has to load.

To solve this only problem, you could pass back the new :id in the body of the response, in some acceptable format:

{"id": 42, ...}

So why the client should follow Location instead of composing its own URL? First of all, the former choice is even less work for the client: it's the server that has to compose an URL to return instead of just dumping a resource. However, what is really happening is that you are separating responsibilities between client and server so that the client knows the basic step of a workflow (create a widget, load it, do some other action on it) and the server governs the actual locations of the response. So the HATEOAS design allows you, the server owner, to change some interesting things in the future:

  • the server may decide to not send the user directly to /widgets/:id but execute an intermediate redirect. For example, some carriers requires this intermediate redirect to one of their pages to allow user identification. If the client just follows Location headers correctly, you can do any number of redirects between the POST on /widgets and the next step /widget/:id.
  • the server may decide to send the user to another host or application altogether. During migrations from legacy system A to new and fresh system B, it may happen that all new widgets that have been created on A are redirected to B after that, in order to phase out part of A gradually and not in a big bang.
  • You can change the internal URLs accordingly, for example putting widgets under /user/:name/widgets/:id where :name is the user that executed the POST. This supports the change of using ids that are unique for a user instead of globally.

I'm not saying you need to appreciate these changes to your system, or that they will ever happen to you; just that this design on a simple creation POST/retrieval GET query allows you to accomodate them without changing the clients (which may be deployed on thousands of Android and iOs devices).

In more complex interactions, where multiple POSTs modify the state of the resource on the server, there are many more new roads that it can take: making some selected clients skip some steps according to business decisions; change the order of operations according to their performance, to leave the quick ones at the start and that awful batch processing at the end, when they can even close the application and be notified later.

Conclusions

If you just need to perform CRUD operations, don't build an object-oriented application, choose a relational database and expose it through some views. In the same way, if you just need to perform CRUD operations with your API, don't expose links in resources: stick to POST and GET requests on fixed URLs. The same goes if you have total control over all clients of your API (in web applications as opposed to mobile applications or other systems that need to integrate you).

But HATEOAS is a model that allows you to allocate to the server some of the responsibilities of your API's use cases: which are the next steps, where they are executed, whether to skip any, or to perform further redirections. HATEOAS isn't a reminescence of WS-* as much as slapping the REST label over remote procedure calls is a reminescence of RMI and CORBA (too many acronyms today!)

mobile app

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • 10 Most Popular Frameworks for Building RESTful APIs
  • Fixing Bottlenecks in Your Microservices App Flows
  • Running Databases on Kubernetes
  • How To Select Multiple Checkboxes in Selenium WebDriver Using Java

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: