7 ms·
HATEOAS: An Alternative Explaination
- eyelidlessness 5y agoTwo things (not exhaustive!) that a JSON (or any data interchange format) API can do to improve discoverability: 1. Provide OPTIONS responses for all resources, clearly and consistently documenting usage of that resource. 2. Provide relevant OpenAPI documentation for those OPTIONS requests, and an interactive UI for GET requests accepting text/html (obvious caveats aside).
- recursivedoubts 5y agoThat's fine and well, but JSON isn't a natural hypermedia and it has struggled to achieve much by adopting hypermedia-like features. I think this is because the power and flexibility of the hypermedia model requires that the consuming entity have agency, and humans consuming HTML (unlike the code consuming JSON) provide that agency: https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.h... Providing more documentation for JSON is an admirable goal, but that isn't the uniform interface of REST, which requires no documentation, just an entry point from which all possible actions are surfaced via hypermedia. Rather it is better documentation for what is a fundamentally RPC model (not bad! just different)
- dragonwriter 5y ago> JSON isn't a natural hypermedia No format is a hypermedia, because hypermedia involves heterogenous formats bound with links. But any format in which links can be conveniently embedded can participated well in hypermedia, and JSON is definitely a format in which links can be embedded. > humans consuming HTML Humans aren't any more the usual consumers of HTML than they are of JSON. In both cases, software consumes and may (or may not) interact with humans. But immediate agency in the consumer isn't necessary for hypermedia, in fact, the hypermedia model is very much intended for robust mechanical consumption by systems not designed with advance knowledge of the structure, because hypermedia is self-describing. That's why web mashups, search engines, archives, and specialized crawlers are all able to work.
- recursivedoubts 5y ago> with advance knowledge of the structure Wouldn't advance knowledge of the structure do away with the benefit of self-describing messages? I assert that, without strong AI or simply passing it along to humans (as with HTML) REST is largely wasted on code.
- deleted 5y ago[deleted]
- dragonwriter 5y ago“bot designed with advance knowledge...” was an unfortunate typo for “not designed with advance knowledge...” Yes, advance knowledge makes self-description superfluous.
- recursivedoubts 5y agoBots can crawl a link graph, but that seems to me to be a relatively primitive use of a uniform interface when compared with a human interacting with a hypermedia system. Does that strike you as well?
- e12e 5y ago> JSON is definitely a format in which links can be embedded. Not really? Html has a way to include links (a/href) json has strings. One can of course add on top of json (like one can build on utf8 text to build json). But json is a pretty terrible format - quite simple, but quite weak. You can embed links in json as much as you can embed a json document as a base64 encoded string inside another json document...
- eyelidlessness 5y ago> natural hypermedia Like, observed in the wild?
- recursivedoubts 5y agoThe second meaning: https://en.wikipedia.org/wiki/Nature_(philosophy) https://en.wikipedia.org/wiki/Nature_(philosophy)
- recursivedoubts 5y agoHello HN. In this article I try to explain HATEOAS in its original context, hypermedia/HTML, rather than using JSON. JSON isn't a natural hypermedia and it makes HATEOAS (and the entire uniform interface of REST) difficult to understand and of frustratlingly little benefit to end users. I don't expect to change the language around REST-ful APIs, where darn near anything over HTTP is called "REST-ful", but I hope that this article will help people who have struggled with understanding what HATEOAS is or why on earth it might be an interesting and useful technology. In its natural environment, HTML, it is much easier to understand.
- bityard 5y agoFirst let me say I love htmx. It's nice to be able to write a little web app with minimal javascript and fuss. It's all well and good to have your API return HTML when your only client is a web browser. And for many applications (like many of mine) that is enough. But HTTP APIs are most powerful when they are client-agnostic. JSON is terrible in so many ways but it is at least neutral ground: it can be consumed by any HTTP client (which need not be a web browser) and every programming language that matters. For my day job, I deal with a great many HTTP APIs that are never seen or used by a browser. Authentication systems, data storage, schedulers, etc I can write a Python script that turns a JSON API response into a native Python object with a single line of code. How can you do _that_ with a HATEOAS response that is basically guaranteed to contain arbitrary HTML?
- littlecosmic 5y agoWith htmx the size and complexity of web client should be radically reduced compared to a heavy JS client app consuming the JSON API. I reckon this could free one up to make an API that was specialised for native clients and possibly even the web server itself… maybe no JSON in sight, unless you were keen.
- zczc 5y agoIf the response is xhtml then de-serialization as easy as with json
- k__ 5y agoShouldn't HTML in the examples be compared to something on the same abstraction level, like HAL? HAL is to JSON what HTML is to SGML. Nobody would argue thst SGML isn't suited for the web, because it too general/low-level of a language.
- recursivedoubts 5y agoThe second example in the article is HAL-like. Leaving the relative poverty of HAL as a hypermedia aside, the crux of the issue in my opinion is that JSON is consumed by code, rather than humans, and thus the flexibility and discoverability of HATEOAS is largely wasted: https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.h...
- k__ 5y agoYes, that might be true, I can't imagine how it should work without a human making decisions on the fly, but that's not a problem of the format.
- recursivedoubts 5y agoI would say it is not a problem of the format in theory, but it turns out to be one in practice. And that using HTML rather than JSON when explaining REST and HATEOAS would be a much more natural approach.
- k__ 5y agoThe second article you linked here makes a much stronger case than the first one. If HATEOAS doesn't work without a human, it's essentially useless for API design.
- recursivedoubts 5y agoI agree, the second article is deeper. The first is an attempt to explain HATEOAS in terms of HTML.
- juancampa 5y agoI looked at HATEOAS a few years ago and thought it would make sense in a latency-free universe. The reality is that waiting for one page to load to know what's next and then waiting again, is a recipe for bad frustratingly slow interactions. Shouldn't we download the whole application "graph" schema upfront? How big could that be?
- recursivedoubts 5y agoThe browser has a built in bit of software called "the rendering engine" which turns HTML strings into visual widgets surprisingly quickly. A javascript application will still need to render to HTML. The few additional attributes necessary for an href are round off errors in the overall scheme of things. I would note that HATEOAS was simply a description of the world wide web. So, in as much as the web worked and continues to work, latency-free universe or not, it appears to be practical for building software systems.
- javajosh 5y ago>The browser has a built in bit of software called "the rendering engine"... FYI if you want to advocate for something, it helps not to condescend to the people you're advocating to.
- dragonwriter 5y ago> I looked at HATEOAS a few years ago and thought it would make sense in a latency-free universe. It makes perfect sense in a latency-laden universe; see, e.g., the Web. > Shouldn't we download the whole application "graph" schema upfront? How big could that be? Arbitrarily large. And it can become stale arbitrarily quickly. But, anyway, HATEOAS is consistent with that if you need it (consider the case where the application data is in a single document and individual resources are accessed by fragment identifiers for one simple example.)
- raihansaputra 5y agoI think this is a spectrum, currently with 2 approaches. The SPA routes mean every client side interaction is responded directly by the app, but still waits for the network. Client needs to download the whole application "graph" though. The HTML way means it doesn't "respond" for the latency period. But with modern tools (like HTMX/Hotwire/Unpoly), devs can start with HTML, and preload certain interactions/use minimal client side JS, instead of delegating all of it into an SPA. E.g.: Client side search/filter https://twitter.com/htmx_org/status/1459549924014669825 https://twitter.com/htmx_org/status/1459549924014669825
- the_arun 5y agoREST APIs are designed to think in platform centric way. Hateoas are designed to extend the same philosophy. I see The HTML example in the article isn't quite that. I mean the last example which renders content in HTML assumes client wants it for a POST call. What if me as a client using it for GET call? Having said that you as a developer is building a HATEOAS form of content in the user interface. Am I reading this right?
- recursivedoubts 5y agoYou as a client have no say in the matter, beyond asking for particular representations which might be presented to you. A REST-ful (in the true sense of the word) system exposes its API to you through hypermedia: links, forms and so forth. You, the human, may interact with it. But there is nothing outside the API provided by hypermedia, no matter how poorly implemented that hypermedia API might be.
- dragonwriter 5y ago> But there is nothing outside the API provided by hypermedia Hypermedia APIs rely on out-of-band definitions of the semantics of media types and the semantics of operations on media types.
- troutwine 5y ago> But there is nothing outside the API provided by hypermedia, no matter how poorly implemented that hypermedia API might be. I've heard this before about HATEOAS and true-REST but I'm always left wondering about odds and ends. For instance, in the deposit example the client is told that the form accepts "amount" which is of type "number". Does this imply that the unit of amount has to be negotiated between server implementation and client implementation out-of-band? Or, to stick to the same example, how should the client behave if the server responds with a 504? Presumably the client and server would need to agree on the protocol for dealing with failures out-of-band, whether retries are allowed, how and if commits work in the system?
- recursivedoubts 5y ago
- dfabulich 5y agoHTTP APIs have been a huge hit, but HATEOAS hasn't. Nobody does it right, nobody "gets it," everybody must have just misunderstood Roy Fielding's dissertation. If only we had a clearer, better explanation, like this one! Unfortunately, this article demonstrates what the industry has known/shown for years: that HATEOAS is unsuitable as a technique for HTTP APIs. Imagine writing a programmatic client against the bank account "API" documented in this article, where the way you'd find out that you can't make a withdrawal is not by checking a "status" in JSON and finding it's overdrawn, but by parsing the HTML and noticing that there's no action link (no `<form>` element!!) that happens to make a withdrawal. Instead of a JSON parser, you'd now need an HTML parser (one of the most notoriously quirky formats in modern use), but not just that, you'd also need your client to read and understand that HTML. For example, where's the error message explaining why you can't withdraw? Why, it's written in the page as user-visible text. Which text is user-visible? Uh oh, now you need to parse and execute the CSS on the page to figure that out, too. You'd need a full-blown browser to do that--a "user agent" as the HTML specification likes to call it--and now, instead of using an API, you're screen-scraping the web site by automating a browser with Selenium or Puppeteer or what have you. What will the client do when the server decides to restructure the HTML? Which one of those <a> links or <form> elements represents withdrawing cash?? It is possible to develop useful tools that automate full-blown websites, but it it's much much easier to develop useful clients when the responses are highly limited in the structure they're allowed to return, to couple the client to the server by committing, in advance, to how the API will work. That's been Fielding's mistake from the very beginning: to think that hypertext provides useful techniques for developing programmatic interfaces. Hypertext is only useful because of its users. Users can read text, understand it, and decide what links to click on or what forms to submit. Programmatic API clients can't afford that luxury. As the article demonstrates, if the client was intended to just be a program, we would never use HTML for any of these exchanges, and especially not use <a> links or <form> elements to convey to that program what is or is not possible. The industry has rejected HATEOS not because we were too stupid understand how awesome it is; we've rejected it because we do understand how awesome it isn't.
- recursivedoubts 5y agoI agree entirely with you and I don't regard it as unfortunate at all that this article shows that HATEOAS is unsuitable for JSON HTTP APIs. It is extremely suitable, and, in fact, is simply descriptive, of an HTML-based API, however. A lot of my thinking around this comes from my work on htmx, a tool that turns HTML into a richer hypermedia: https://htmx.org https://htmx.org And I am actively encouraging people to try to split their thinking about JSON Data APIs (RPC) and REST-ful HTML-based systems.
- rektide 5y agoI 100% am onboard. I think this article still undersells how vital a shift it is, whether you are using a programming-oriented representation JSON, or the web's de-facto and de-jure representation of information HTML (un-discussed but key to me is RDFa and Microdata semantic-markup). This article is so good, draws a very clear picture, & yet it's still no-where enough in de-lineating just how key it is, how vital it is, that the actual web medium- HTML- be able to & be used for expressing information. It at least makes a solid go at trying to show how JSON is arbitrary, where-as HTML is definitive, declarative, expressive. Back in DHTML days we talked about "data islands", which could be either JSON or XML/XHTML/HTML, either embedded in the page, powering the JS & webapp. Allowing the data & page realm to remain separate is a huge mistake. It overlooks the reverence & respect we ought/need to have for the core source of truth, for the real medium, HTML. Programmers need to take a knee & respect the vital, core, discoverable, honest truth of the web: HTML >>> JS. JS is supposed to just be a tool. As a agnostic/near-aetheist, it still feels non-contradictory to me to say we have fallen away from god in our march towards JS-driven applciationization. We have served illegitemate interests.
- Osiris 5y agoThis article seems to just be describing plain-old HTML. You make a request to a URL, get back HTML, render the HTML. The HTML has forms and links that you click and get back new HTML. I don't see how this is an API at all. It's just (server-side rendered) HTML.
- dragonwriter 5y agoREST, including the principle of HATEOAS, is an architectural style derived as a generalization/rationalization of the early web design and explicitly underlying HTTP 1.1, so an explanation of HATEOAS looking like a normal use of HTML on the web is not at all surprising. The Web itself is a distributed hypermedia API.
- BlackFly 5y agoIt is an API that you program against when you want to build a client for that API. That client is a browser, the most famous of which are Chrome, Firefox, Safari, Edge, Opera, etc. The HATEOAS constraint is what allows the actual form of (for example) a webshop's checkout to start asking for additional details from one day to the next without me needing to update the client. The Hypermedia is indeed HTML, images, movies, javascript, style files, etc. HTML contains the embedded links to navigate around a webshop, the form controls tell the browser what it needs to POST to a url (and that it needs to POST or PATCH). To do something like that with a data API, the form the data must be comprehensible a priori and the client must be able to know the form of the data dynmically. This means either a large (or small like the web) registry of types of data that you are limited, or some sort of link + schema that the client can understand. If you build such an API, and I build a client, then my client will also naturally work on anyone else's web application that follows the same constraint. That is, my client will be universal. It turns out that nobody web browsers really want or need a universal client. If you want to see an example of what that looks like in practice, check out JSON-LD at https://json-ld.org/spec/latest/json-ld/ https://json-ld.org/spec/latest/json-ld/ or other specs like it.
- brabel 5y ago> I don't see how this is an API at all. That's absolutely an API... perhaps what you think of as an API is too narrow in scope?
- shrubble 5y agoAs someone who has worked as part of a team on an Angular 9.x frontend with Spring Boot Java backend mediating between many other backend API based services... well, it's a huge mess, a resource hog in terms of disk, RAM and CPU, and far slower than it could be. Development is slow and cumbersome and the browser uses 48MBytes+ on the page for what is ultimately a slightly complicated CRUD app. Thr JSON APIs are secured by tokens and other mechanisms, so you can never query them directly without the Angular app. We have 800MB or more in node_modules with Node taking 100s of MB and the Java backend uses over 1GB of RAM in dev mode just to start up. It's an internal application available over the VPN. Even with high speed internet some API calls take 2 seconds to return and populate parts of the form in edit mode. A single unified backend server pumping out html would likely be both faster and easier to manage.
- tunesmith 5y agoNot sure how this is related to HATEOAS, but having one api backend to front several private services is a pretty common pattern. But as a data point, I can tell you that with us using a react frontend to talk to a nodejs graphql backend that also fronts private services, our nodejs graphql backend is usually below 300mb of ram. At any rate, it sounds like your spring boot app combined with your network topology is the constraint, good luck chipping away at it.
- kragen 5y agoPerhaps you posted this comment on the wrong thread, because it doesn't seem to pertain to the article at all.
- shrubble 5y agoWe have state in two places and have to talk to 3 servers (frontend Angular/Node, java middleware and databases behind that) to serve a page, with JS running continually on the browser to monitor changes in variables etc.. Isn't the idea that you have a server that serves static or nearly static html to the browser? And maintains the state on the server itself. We can't easily do what the LISP guys call memoization, which would be a huge win for performance by keeping properly cached values on the server, for example.
- ThrustVectoring 5y agoIMO, the benefits of HATEOAS are very much overblown - many circumstances you have full control over the version of both client and server, and all it is doing is adding an extra layer of indirection that allows extra complexity and ambiguity to sneak in. Instead of the client depending on a specific known API endpoint, it depends both on the endpoint you give it at runtime and the process that serves that endpoint to the client. And as a bonus, the client now "helpfully" obfuscates what endpoints it needs to render which pages - what you could figure out with straightforward grep for something like "api/v1/books" now needs a deeper understanding of the application. Like, the way in which the client accesses the "deposits" functionality is either fixed or can dynamically change. If it's fixed, the indirection serves no purpose - just have the client do the thing in the one way that you ever have the client do the thing. If it can dynamically change, the state space involved can and often will grow out of control in a hurry, and I strongly suggest pushing back on designs that require structural dynamism like this.
- berkes 5y agoYou may not have encountered another use-case. This is not only about design-time versus run-time. But a large part about "where to have business-logic". Say simple use-case where you have web/android/ios clients, which show an invoice after the payment is processed (and not cancelled, pending, halted, flagged-for-terrorist-double-check, or whatever banks come up with tomorrow). You either have one service determining "there is an invoice" or "there is no invoice", or you have all your web/andoid/ios clients implement this logic and have to keep it in sync. Not only is this flakey, it introduces very tight coupling to fields and their values. I've seen abominations such as `status == "pending" || status == "PENDING" || status == "PendingValidation" && validation == false`, (edit) repeated in every client (and obviously slightly different). Moving this to a single point of truth comes with a lot of benefits. But when you don't ever have such business-logic, by all means, skip all the indirection and just render whatever comes back, based on a swagger doc you read for version x.y.
- ThrustVectoring 5y agoYou don't need to go full HATEOAS to consolidate most business logic in server-side API. Like, this is just an example of an awkward API that exposes `status` and `validation` and makes clients do the business logic, rather than one that exposes `hasInvoice` and/or `invoiceId`. The HATEOAS bit is sending across a URI instead of a resource ID, which only helps when there's business logic for which endpoint to use for a specific resource ID that needs deduplication. And even that is only necessary when the client must make the request directly and can't proxy through a "figure out which endpoint to use and delegate it" endpoint. To be specific, HATEOAS would help when Visa and Mastercard need to use different endpoints for the invoice, and the payment networks require the client to directly query their endpoint rather than going through a server API you control.
- PostThisTooFast 5y agoI will give the article credit for finally providing an example of how hyperlinks returned along with a result are used to inform a person of what to do: by returning a FORM. I've read many an article about HATEOAS that doesn't mention exactly HOW these links are useful. Still, they seem useful only for human, manual operation. A bunch of links provides no indication of their purpose other than a textual description.
- kitd 5y agoLots of excellent points in the article, but the problem I have with it (and HATEOAS in general) is that, like NakedObjects before it, it expects the model of the resources and what you do with them to mirror precisely the model the user understands and wants to do. Ie, it takes no account of UX and design principles. As a result, you end up with rather CRUDdy noun-oriented systems that don't really flow, with resources randomly thrown around by developers to try and make it make logical sense. A kind of accidental hypermedia complexity. I love the abstract concept of HATEOAS, but it needs some overarching architectural abstractions to help designers and developers implement just the resources and links needed. A great research opportunity there IMHO.
- berkes 5y agoQuite often, using nouns actually improves your architecture (and your Ubiquitous Language[0]). This design constraint is often one that pushes you in the right direction, but you have to allow it to push you. E.g. the classic "I want to archive this ticket". Three common approaches: POST/PUT /coupons/1337/archive PATCH /coupons/1337 { archived: true } POST/PUT /coupons/1337/archivals Designer now gives up. The second option is technically often the easiest (esp with CRUD frameworks like Laravel or Rails) but design wise by far the worst. The first is RPC-style and the last is suffering from what parent describes > As a result, you end up with rather CRUDdy noun-oriented systems that don't really flow What we see, however, is that our UL is lacking. What is it that we really do. What do we end up with?[1] We might "copy it to the archives" or "relocate it to the archives" etc, depending on your business case and domain details. We request a "relocation", which, when resolved, results in an "archived ticket". POST /archives/tickets/ { ...the entire ticket } or POST /tickets/1337/relocations It now adheres to REST, better describes the domain language, is consistent and flows quite alright. EDIT: the latter, for example, communicates that this may take a while (async), results in the ticket being moved elsewhere and the original one probably redirecting to the new. The former communicates clearly that we are making a copy or snapshot of the ticket in the archives. But there will always be cases where the verb makes more sense or adheres much better to the UL and domain. In such cases, one can still be resource-full and REST-full without introducing awkward nouns. E.g. in an CQRS setup, we interface with Commands. We can then request commands: `POST /commands/archive_ticket_command/` for example. --- [0] https://www.martinfowler.com/bliki/UbiquitousLanguage.html https://www.martinfowler.com/bliki/UbiquitousLanguage.html [1] Sidenote: I try to avoid words that are both a nound and verb. Like "archive". To archive vs In the archive: this causes ambiguity.*
- AmericanBlarney 5y agoI'm a big believer that HATEOAS serves no actual purpose. Adding a layer of indirection is pointless - messages get bloated by URLs the client virtually never needs. For the vast majority of APIs, URL structures don't change that often and, when they do, it often indicates changes to content being transmitted, which would require business logic updates anyway. For making APIs forward/backward compatible, both GraphQL and Protobufs are better options.
- recursivedoubts 5y agoAs with many other comments in this thread, I agree with you, but only in terms of JSON APIs. The article is an attempt to explain HATEOAS in terms of HTML (or hypermedia) where it has a purpose and, in fact, is simply the natural state of affairs.
- User23 5y agoI’m disappointed that the initial vision of the web where the user-agent is an editor and not a browser was abandoned. Playing around with Nyxt has given me a glimpse of how that might have looked.
- hermanradtke 5y agoThe html on this page also contains URLs that you will never click. The real problem with HATEOAS for JSON APIs is that we have never built the proper client. With html, you can rewrite your entire website and the browser will happily render the new pages. When people start writing such a client for JSON, the JSON starts to look very similar to html.
- criddell 5y agoThe last two sentences are: > While attempts have been made to impose more elaborate hypermedia controls on JSON APIs, broadly the industry has rejected this approach in favor of simpler RPC-style APIs that forego HATEOAS and other elements of the REST-ful architecture. > This fact is strong evidence for the assertion that a natural hypermedia such as HTML is a practical necessity for building RESTful systems. This all sounds about right to me and makes me ask what the problem actually is? Maybe an RPC-style API is a better choice for most systems?
- recursivedoubts 5y agoThe success of the web argues that the hypermedia approach is a good choice for a large set of systems. The problem today is that hypermedia development has been stuck in the late-90's/early-00's which, when contrasted with JSON/RPC-based development, is really showing its age, particularly in terms of UX. https://htmx.org https://htmx.org is an attempt to rectify that situation and get hypermedia-style development back in the game as a viable, modern network architecture for more than just content-oriented web sites.
- criddell 5y agoI was looking at that site a bit earlier today and I guess I still don't understand the motivation. On the "Htmx in a Nutshell" page you say: > This keeps you firmly within the original web programming model, using Hypertext As The Engine Of Application State without even needing to really understand that concept. Why is the original web programming model worth consideration? Why choose a RESTful API over a more RPC-like API?
- recursivedoubts 5y agoSome reasons you might want to use hypermedia over an RPC-like API: - The simplicity of the model (e.g. The "active search" pattern can be implemented with a few hypermedia attributes in htmx: https://htmx.org/examples/active-search/ https://htmx.org/examples/active-search/) - The flexibility of the uniform interface[1] (e.g. versioning your API is much less of a concern) - The ease of deep linking
- gabesullice 5y agoI like this piece because I think it does a good job explaining the purpose of HATEOAS. The author is right that JSON can obscure its usefulness and HTML is a more familiar way to demonstrate it. However, the author neglects to mention or is unaware of link relations, which can document and prescribe actions to take on a link just as "action" and "method" prescribe how a browser should submit a form. Link relations can fix the <form> problem of JSON as a hypermedia format by prescribing the actions a client must take in order to follow a link. This is what the "action" and "method" of the form element do and these could be defined as target attributes of a "deposit" link represented with JSON. The author is correct about pure JSON, but JSON-based media types like application/hal+json, JSON-ld, and application/vnd.api+json are very workable. Using these allowed my team to implement a decoupled React application with a JSON API back end. We used link relations similar to the banking example and our team was able to add and remove deposit-like links and add new buttons for previously unplanned operations without updating any JavaScript. Full disclosure: I'm an editor of the JSON:API spec (i.e. application/vnd.api+json)
- jounker 5y agoWorst acronym ever. Hate-Oa’s. Sounds like a white supremacist breakfast cereal.