i am the creator of htmx & obviously glad to see it get some attention, but I also don’t want to overpromise what it can achieve. I think it makes a lot more possible in within the hypermedia paradigm of the web but, of course, there are times when it’s the right choice and times when it isn’t.
i have been working on a free book on hypermedia-based systems with a few other authors here:
I would say that in 99% (or more) of the existing http request DELETE and PUT are replaced by POST, and using something different is likely to break something, for little benefit
for exemple if you make two DELETE which should be idempotent and that your backend doesn’t treat them in a non idempotent way, your app is suddenly having a bug which can be hard to reproduce.
Not sure I get your point. If your backend is treating deletes as not idempotent you’re already wrong. And deletes in particular seem like a quite easy to make idempotent, just check if it has been deleted already before deleting.
What does it mean to delete something? Should I use DELETE if it’s a soft delete? What if can be undone for three hours? What if it deletes one thing but adds an audit record somewhere else?
DELETE adds nothing. The point is “can an intermediary cache this?” If yes then use GET. If not, POST.
URL paths are function names. The arguments to a GET function are query parameters. The arguments to POST functions are a JSON body (or form fields if you’re doing AJAX). You make up requests and responses that fit the domain instead of assuming everything is a resource with the same verbs. I’m also against putting resource IDs into URLs for APIs (you can do it for stuff end users see to make the URLs pretty, but not for APIs).
You make up requests and responses that fit the domain instead of assuming everything is a resource with the same verbs.
Aren’t you just stating that you prefer RPC, without actually engaging with the argument for hypermedia?
The argument is that “Uniform Interface Constraint” (resources with a standard set of methods) allows you to make general clients that can interact with your resources with no out of band information (like API docs), a la web browsers + html.
Admittedly, what you describe is, in fact, how the majority of most APIs today work, and there is an interesting discussion about why that is if hypermedia supposedly has so many advantages.
I think your argument would be more interesting if you stated why you think that goal doesn’t have value, especially given that the web itself works that way, that it solves problems like API versioning, and so forth.
I’m also against putting resource IDs into URLs for APIs
Why do you not like this specifically, out of curiosity? What do you prefer?
Second question first, resource IDs belong in query parameters. HTTP has many overlapping ways of sending data from client to server and server to client. The client can send information as a method verb, a URL path, a query parameter, a header, or a request body. There has to be some system to organize the arbitrary choices. The system is:
Verb is for read vs write.
URL path is the function to call.
Query parameters are the arguments to reads. Bodies are the arguments to writes.
Header is for authentication.
IDs are prettier in the URL path, but for an API, that doesn’t matter. You just need a convention that is easy to follow.
As for Hypermedia, I just care that the website is good for users and developers. Whatever the theory is behind it isn’t very important. It’s great that web browsers are universal tools, but that’s true for JSON APIs too, so “hypermedia-ness” only matters if it makes development easier or harder. I think probably HTMX is easier for most web apps, so that’s why I like it. Even then, I’m more partial to Alpine.JS because I feel like the core motivation for a lot of the HTMX partisans is just wanting to avoid learning JS.
I feel like the core motivation for a lot of the HTMX partisans is just wanting to avoid learning JS.
I know this is a selling point, but fwiw I have a lot of JS experience, consider myself good with it, have used React and other similar frameworks, but still like the simplicity of the old MPA model – htmx being for me just an upgrade. Having just the single data model of the resources on the server to think about it.
The system is:….
Agree with your point about “overlapping ways of sending data from client to server,” and also agree that having any clear system is more important than “the best system,” if there is one. I guess I’m not seeing why the classic system of “url path to describe resource”, “http verb to describe action” is not good enough… It can be stilted and noun-y, yes, but imo that’s not enough reason to throw away a perfectly good existing “system,” as it were.
I don’t like the classic “everything is a noun” system because it ends up needing a lot of requests to get anything done, and requests are the slowest thing you can do with a computer.
I’m working with the MailChimp V3 API this week, and to send a campaign takes three requests: 1. Create campaign 2. Set content 3. Send. In MailChimp API V2, it’s a single request, but they’re finally shutting it down at the end of the month, so I’m being forced to make the change. Because it’s three requests instead of one, I probably need to put it into a queue now because it won’t be reliably fast enough to get done in one request for my users, so now I have to deal with all the complications of asynchrony, and for what? The old API was better.
Seems like a reasonable complaint but orthogonal to the naming/noun-ness of the system. They could continue to support the version you prefer with something like POST “api.mailchimp.com/one-shot-emails” or “outbox” or whatever. That is, from a pure naming persepective, you can always transform back and forth between the two systems.
To your point, classic REST typically has aggregate endpoints return a list of ids, and then you have to make requests (possibly parallel) to each id resource to get the details, which is cumbersome. But nothing forces you to follow that if it doesn’t suit your use-case.
I call this “BrowserTP” since it’s a squished down version of HTTP based on what browsers supported in the early 00’s.
I would say thusly: HTTP is an RPC protocol where the method name (or function or procedure name if you wish) is the method (sometimes called the verb). The URL path is the object that you are calling the method on. The arguments are query string + body as you say.
And sure I can say “please create a deletion for the element in this collection with id 1” it’s not wrong per se, but why wouldn’t I just say “please delete element 1”
I agree that they aren’t really useful, but it takes very little effort for the author to add them and a lot of people want them.
Aside from the obviously minor difference of sending POST /thing/delete vs DELETE /thing, other HTTP verbs can introduce additional overhead with CORS:
Additionally, for HTTP request methods that can cause side-effects on server data (in particular, HTTP methods other than GET, or POST with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with the HTTP OPTIONS request method […]
I was going to argue the opposite with approximately the very same line quoted.
If you and your webapp rely on the browser for some of the protection against some level of cross-site request forgery attacks, you can use the verbs as they were intended and rely on the browser to enforce them to be usable according to CORS rules.
i want to say that it add complexity: if you have a reverse proxy, it has to support the new verbs, if you have logs it should be aware of this verbs, if you have something in your infrastructure which used to ignore DELETE, and suddenly support it, it suddenly delete unwanted things
As a long time SPA apologist and licensed reverend of the church of tiny backends, I find this genuinely difficult to follow. What is “hypermedia” even? A tree with some implied semantics? How is that different than any other data? Why should I be constructing it on the backend (that place that knows comparatively nothing about the client)?
The back button has been solved for over a decade.
The complexity of “the backend has to care what things look like” is also enormous.
Theres talk of longevity and churn, but I’m pretty sure if I wrote hx-target=... in 2012, I would not get the desired effect.
I haven’t managed state on a server beyond session cookies and auth in ages.
I saw a computer from 20 years ago use the internet just fine last weekend, and it needed some horrifying reverse proxy magic to make a secure connection, so “I’m using HTTPS” and “I’m supporting old hardware/OSs” is a contradiction anyway because decrypting HTTPS is more computationally intense than doom, and it’s also a moving target that we don’t get to pin. The end result is that if you can securely exchange information with a browser, it’s not ancient enough to need more than a few servings of polyfills to run a reasonably modern app.
React is the currently popular thing that makes stuff go vroom on the screen, so of course a lot of people make it more complicated than it needs to be, but like… remember early 2000s PHP CMSs? Those weren’t better, and if you did those wrong it was a security issue. At least a poorly written react UI can’t introduce a SQL injection.
To each their own, but I don’t get it 🤷♀️. I also don’t get how people end up with JS blobs bigger than a geocities rainbow divider gif, so maybe I’m just a loony.
Anything can be done wrong, and the fact that popular tools are used wrong often and obviously seems like a statistical inevitability, not a reason to try to popularize something different.
not a reason to try to popularize something different.
Why would you prevent people to popularize anything that actually solves some problems? Isn’t having choice a good thing? I’m this author of this talk about a React->htmx move, and I’m completely freaked out by how many people have seen my talk, as if it was a major relief for the industry. I am also amazed, when hiring young developers, by how most of them don’t even know that sending HTML from the server is possible. Javascript-first web UI tools have become so hegemonic that we need to remind people that they have been invented to tackle certain kind of issues, and come with costs and trade-offs that some (many? most?) projects don’t have to bear. And that another way is possible.
Anything can be done wrong, and the fact that popular tools are used wrong often and obviously seems like a statistical inevitability,
Probably the statistics are way higher for technologies that carry a lot of complexity. Like I said in my talk, it’s very easy for JS programmers to feel overwhelmed by the complexity of their stack. Many companies have to pay for a very experienced developer, or several of them. And it’s becoming an impossible economical equation.
The complexity of “the backend has to care what things look like” is also enormous.
With htmx or other similar technologies, “what things look like” is obviously managed in the browser: that’s where CSS and JS run. Server-side web frameworks are amazingly equipped for more than a decade now to generate HTML pages and fragments very easily and serve them at high speed to the browser without the need of a JS intermediary.
young developers … most of them don’t even know that sending HTML from the server is possible
I am shocked and stunned every single time I talk to someone who doesn’t know this. And if they are interested, I explain a little bit about how the web server can return any data, not just json.
Hypermedia encapsulates both current object state and valid operations on it in one partially machine-readable and partially user-readable structure.
A lobsters page, for example, lists the link and comments (the current state) and has a definition of how to comment: you can type in text and post it to the server. After you do that, the system replies with the updated state and possibly changed new valid operations. These are partially machine-readable - a generic program that understands HTML* can see it wants text to post to a particular server point - and partially user-readable, with layout and English text describing what it means and what it does.
Notice that this is all about information the backend applications knows: current data state and possible operations on it. It really has nothing to do with the client… which is part of why, when done well, it works on such a wide variety of clients.
hypermedia doesn’t have to be html either, but that’s the most common standard
What kind of apps are better in HTMX vs. Rails Hotwire [1] or Phoenix Liveview [2] ? Honest question
The latter both aim to consolidate logic on the server side and reduce JavaScript, even more so than HTMX it seems
I’m not an experienced web dev, but I do know vanilla HTML, JS, CSS pretty well
I’m looking for some higher level abstractions to make an app, so I don’t have to re-invent the wheel.
A possible problem I see in HTMX is that it looks very “declarative” – and declarative systems are often convenient in the 80% case, often fall off a cliff for the other 20%. In my experience an app always needs “a bunch of special case code” somewhere – otherwise it wouldn’t be worth using/writing.
It seems like with Hotwire/Liveview the idea is that you have the full power of either Ruby or Elixir, which are general purpose languages.
Also, if you want to use less JavaScript, then HTMX is still seems like it must be a pretty big JavaScript library? Is it interpreting all the attributes and generating dynamic behavior in the browser?
Also being agnostic of the server side could also be a downside. That means you don’t have any real integration with what happens on the server?
htmx and Hotwire are pretty similar, so it’s mostly a matter of preference which you use.
LiveView is quite different: instead of using HTTP and large-grain data exchange, it uses websockets and sends fine-grained updates. It’s basically a remote SPA. The downside is that you need to keep an Erlang process alive for each session, for the duration of the session. Erlang processes are famously very light and meant to be restarted when they crash, and as a result, this actually works.
htmx, on the other hand, is more of an extension to HTML (hence the name). Imagine the classic links-and-forms approach of building web apps, and then extend it:
Partial replacement in addition to full-page navigation (related to what hypermedia theorists call “transclusion”, but triggered by user interaction)
Methods other than GET and POST (why is this still a constraint in 2023?)
Wider range of interactions other than link clicks and form submissions
These simple additions massively reduce the number of cases where JavaScript is needed.
In my experience an app always needs “a bunch of special case code” somewhere
Our experience agrees, in fact, we wrote a whole programming language aimes at a bunch of special-case code (see later). In our experience, events are the best way to glue JavaScript code together. htmx emits custom events for everything it does, and can use any native or custom event as well.
For writing your special-case code, there are a few solutions:
If it only affects a specific widget, it should probably be inlined. Writing JS inline sucks, so there are libraries like Alpine.js (very good at handling events, closer programming model to SPA frameworks) and our own _hyperscript (a new programming language with events built-in so you can do stuff like “loop until mouseup”, the thing I was talking about earlier)
If it’s a more reusable behavior, the RSJS pattern is a great way of organizing that sort of code. “Behaviors” as defined there are a much better abstraction than “components” in my {opinion,experience}.
It seems like with Hotwire/Liveview the idea is that you have the full power of either Ruby or Elixir, which are general purpose languages.
[…]
Also being agnostic of the server side could also be a downside. That means you don’t have any real integration with what happens on the server?
Again, Hotwire and htmx use very similar models, and Hotwire is actually backend agnostic as well. With htmx, you have the power of $FAVORITE_LANGUAGE .
“Integration” with server side can be useful, but it can also be problematic. It means the framework needs more control over your application. (see also: every npm package foo having a wrapper library react-foo). It also means the framework codebase has a network boundary cutting across it. (never try to abstract away a network boundary!)
Also, if you want to use less JavaScript, then HTMX is still seems like it must be a pretty big JavaScript library? Is it interpreting all the attributes and generating dynamic behavior in the browser?
It’s about writing less JS rather than the amount shipped to the browser. Although 14kb min.gz is not that bad, no? (for reference, React seems to be around 44kb). We’re not trying to replace JavaScript, just the parts that should have been in HTML in the first place.
I’ll try to bring clarifications (I only know HTMX).
HTMX vs. Rails Hotwire [1] or Phoenix Liveview [2]
First off: HTMX and Hotwire are framework and language-agnostic, Liveview is not. That’s already a big deal! It is not “Rails” Hotwire (?)
AFAIK, Liveview is geared towards real-time changes, think reactive double-data binding à la . A Liveview connection lives on websockets, HTMX sends regular requests to the server.
In HTMX, there is no “double data binding”, but you can update and replace several parts of the DOM in one request. Like: clicking this button sends a GET to the server, it does its logic and returns 3 fragments of HTML for 3 distinct parts of the DOM: update the button, update the total showing at the top of the page, update a menu entry on the left (or whatever). All this, without writing JS, without a page reload.
In my experience an app always needs “a bunch of special case code” somewhere
So, it’s in the server? Or, as the author said, sometimes HTMX isn’t appropriate. If you want pure client-side reactivity, you’ll need a bit of JS. The options are many: a vanilla snippet, Alpine, or a JS framework.
It seems like with Hotwire/Liveview the idea is that you have the full power of either Ruby or Elixir, which are general purpose languages.
With HTMX (and Hotwire IIUC) you get the full power of your language of choice. So I was able to add HTMX in my current Django or Lisp apps without any issue.
Also being agnostic of the server side could also be a downside. That means you don’t have any real integration with what happens on the server?
Not sure I understand the concern but I think you’re right: HTMX returns HTML fragments in order to update the DOM, not data in JSON that would inform a JS layer about the state of the server.
We are not talking about another neat library: https://unpoly.com/ Similar to HTMX, but (for the little I tried) it goes even further because it offers some widgets. For instance, you have two different static pages? Unpoly has a declarative way to turn one into a modal of the other.
HTMX is on my “things to try” list and I think its approach makes a lot of sense for many kinds of web apps. I love a lot of its design choices.
At the same time, I think the author neglects to mention some of the arguments against using it. The most obvious one: “Hey, can we make a mobile app too?” The React people will whip out React Native and reuse the server interaction code from the SPA. Their backend colleagues will barely have to do any work since it’s just another caller of the existing API. The server-rendered-HTML people, though, will scramble to design a native-app-friendly API from scratch and will be stuck maintaining two request-handling code paths to work with the same underlying data.
“We have several kinds of clients some of which aren’t web browsers” is a common enough scenario in my experience that I don’t think any HTML-centric approach is likely to be “the future” in the broad sense the post suggests. But it, or something like it, probably has a place in the future.
can we make a mobile app too? […] maintaining two request-handling code paths to work with the same underlying data.
Maybe is it the goal of Hotewire’s Strada? (upcoming in 2023)
“This makes it easy to progressively level-up web interactions with native replacements.”
The “HTMX for mobile” seems to be Hyperview: https://hyperview.org/ (from the hypermedia.systems book)
“Hyperview is a new hypermedia format and React Native client for developing server-driven mobile apps.”
(it says “server-driven” and “networked mobile apps” and warns: “If your app relies on offline data or local computations, Hyperview won’t be the right choice.”)
I do agree that HTMX is all-in on the web, and it’s not suitable for native mobile apps. I have made a decent PWA with it, though, and compared to comparable SPAs it runs like greased lightning in a mobile browser.
That said, for a lot of things, you really could take the same approach as the article does for serving HTMX fragments vs full pages — check for an Accept: application/json header, return the appropriate JSON representation after doing the same logic you would for HTMX or no-JS. The client would have to be from scratch, yeah, you don’t get the benefits of something like React Native, but the backend still barely has to change.
I’d be really interested to hear more about a PWA in HTMX. Is the service worker very app-specific (like knowing how to render data to HTML) or more generic (like caching visited pages)? Do you end up duplicating logic between the server and service worker, or did you find a good way to divide it up? Or did you try to share the logic somehow?
For my app, it was pretty much just caching and serving some static internal pages. Since the service worker has to be in JS, I didn’t want to make it too involved. My main goals were just to make the app installable on a phone home screen, and to do something sensible when offline.
It obviously depends on the app. HTMX is primarily targetting hypermedia not rich clients, so a mobile app is often not relevant. However, it would also not be a big deal to write a hypermedia client for mobile that was more limited/special case than a browser if you do need an app, and reuse the HTML descriptions etc without using a webview.
I don’t think it’s the future, but I definitely think it’s /a/ future. The way I see it, when you write an SPA-style front-end application, you take on the responsibility of writing the /entire/ application, where HTML and CSS are only used as graphics primitives, and you don’t/can’t rely on the browser for any functionality other than running your JS/Wasm VM. There are, certainly, web applications that require this — Infinite Mac being one of my favorites. But if you don’t want to, don’t need to, or can’t take on that effort, and want to leverage all the work that browser vendors have already done, HTMX is a better choice.
I’ve written several apps using HTMX and its predecessor, Intercooler.js, with either Django or ASP.NET MVC on the backend, and it’s always been a joy. One thing I’ve particularly appreciated is how it lets you really leverage the server-side templating libraries to use the same partial views in generating both full pages and HTMX responses.
How would you make something “live” like an animation or an interactive chart?
Security is often about limiting attack surface. With a REST/JSON approach, I can have an extremely limited number of powerful endpoints (like 20 for an entire large application, each tested, audited, profiled). In this case, I can imagine ending up with hundreds or thousands of endpoints. What does that mean for security? And if one endpoint is slow, then DDOSing will be a walk in the park.
Lol, it depends how you wrote it. hx-trigger allows you to perform AJAX requests off of Javascript events, but I don’t know, I wouldn’t know how to correctly implement Datadog’s complex solution myself either.
Probably not with native htmx, because there seems to be some smart-ass stuff there to linearize back-end requests.
But: one of the reasons these dashboards need to be optimized is that they are in charge of both requesting data and creating DOM nodes based on received data. If your architecture is hypermedia-oriented, the client app is only in charge of requesting HTML widgets from the server, and the HTML itself is rendered by… the browser, which does that in a pretty optimized way.
So maybe we’re talking about one of the few use cases where htmx wouldn’t do the trick, but I’m not sure the hypermedia approach wouldn’t be relevant. And we’re talking about a non-trivial use case of a company that has a huge tech team.
* for some stuff[1]
i am the creator of htmx & obviously glad to see it get some attention, but I also don’t want to overpromise what it can achieve. I think it makes a lot more possible in within the hypermedia paradigm of the web but, of course, there are times when it’s the right choice and times when it isn’t.
i have been working on a free book on hypermedia-based systems with a few other authors here:
https://hypermedia.systems
[1] - https://htmx.org/essays/when-to-use-hypermedia/
I don’t get why htmx allow other http verb than GET and POST. from my point of view it add a layer of complexity without real benefit.
Are you saying DELETE and PUT should be replaced by POST? The idempotence property of these operations would be lost if you did that.
Yes. Other verbs are a waste of effort. They don’t benefit anything and it adds another design decision you don’t need to make.
I would say that in 99% (or more) of the existing http request DELETE and PUT are replaced by POST, and using something different is likely to break something, for little benefit
for exemple if you make two DELETE which should be idempotent and that your backend doesn’t treat them in a non idempotent way, your app is suddenly having a bug which can be hard to reproduce.
Not sure I get your point. If your backend is treating deletes as not idempotent you’re already wrong. And deletes in particular seem like a quite easy to make idempotent, just check if it has been deleted already before deleting.
Being limited to get and post was the biggest mistake forms ever made and held the web back for years with shitty hacks like ?_method=DELETE
What does it mean to delete something? Should I use DELETE if it’s a soft delete? What if can be undone for three hours? What if it deletes one thing but adds an audit record somewhere else?
DELETE adds nothing. The point is “can an intermediary cache this?” If yes then use GET. If not, POST.
But then how are you going to indicate a delete action? Just make up something to stuff in the post body? How is that any better?
URL paths are function names. The arguments to a GET function are query parameters. The arguments to POST functions are a JSON body (or form fields if you’re doing AJAX). You make up requests and responses that fit the domain instead of assuming everything is a resource with the same verbs. I’m also against putting resource IDs into URLs for APIs (you can do it for stuff end users see to make the URLs pretty, but not for APIs).
What does the R stand for
clearly the R stands for RPC ;)
Right tool for the job.
Aren’t you just stating that you prefer RPC, without actually engaging with the argument for hypermedia?
The argument is that “Uniform Interface Constraint” (resources with a standard set of methods) allows you to make general clients that can interact with your resources with no out of band information (like API docs), a la web browsers + html.
Admittedly, what you describe is, in fact, how the majority of most APIs today work, and there is an interesting discussion about why that is if hypermedia supposedly has so many advantages.
I think your argument would be more interesting if you stated why you think that goal doesn’t have value, especially given that the web itself works that way, that it solves problems like API versioning, and so forth.
Why do you not like this specifically, out of curiosity? What do you prefer?
Second question first, resource IDs belong in query parameters. HTTP has many overlapping ways of sending data from client to server and server to client. The client can send information as a method verb, a URL path, a query parameter, a header, or a request body. There has to be some system to organize the arbitrary choices. The system is:
IDs are prettier in the URL path, but for an API, that doesn’t matter. You just need a convention that is easy to follow.
As for Hypermedia, I just care that the website is good for users and developers. Whatever the theory is behind it isn’t very important. It’s great that web browsers are universal tools, but that’s true for JSON APIs too, so “hypermedia-ness” only matters if it makes development easier or harder. I think probably HTMX is easier for most web apps, so that’s why I like it. Even then, I’m more partial to Alpine.JS because I feel like the core motivation for a lot of the HTMX partisans is just wanting to avoid learning JS.
Thanks for explaining.
I know this is a selling point, but fwiw I have a lot of JS experience, consider myself good with it, have used React and other similar frameworks, but still like the simplicity of the old MPA model – htmx being for me just an upgrade. Having just the single data model of the resources on the server to think about it.
Agree with your point about “overlapping ways of sending data from client to server,” and also agree that having any clear system is more important than “the best system,” if there is one. I guess I’m not seeing why the classic system of “url path to describe resource”, “http verb to describe action” is not good enough… It can be stilted and noun-y, yes, but imo that’s not enough reason to throw away a perfectly good existing “system,” as it were.
I don’t like the classic “everything is a noun” system because it ends up needing a lot of requests to get anything done, and requests are the slowest thing you can do with a computer.
I’m working with the MailChimp V3 API this week, and to send a campaign takes three requests: 1. Create campaign 2. Set content 3. Send. In MailChimp API V2, it’s a single request, but they’re finally shutting it down at the end of the month, so I’m being forced to make the change. Because it’s three requests instead of one, I probably need to put it into a queue now because it won’t be reliably fast enough to get done in one request for my users, so now I have to deal with all the complications of asynchrony, and for what? The old API was better.
Seems like a reasonable complaint but orthogonal to the naming/noun-ness of the system. They could continue to support the version you prefer with something like POST “api.mailchimp.com/one-shot-emails” or “outbox” or whatever. That is, from a pure naming persepective, you can always transform back and forth between the two systems.
To your point, classic REST typically has aggregate endpoints return a list of ids, and then you have to make requests (possibly parallel) to each id resource to get the details, which is cumbersome. But nothing forces you to follow that if it doesn’t suit your use-case.
I call this “BrowserTP” since it’s a squished down version of HTTP based on what browsers supported in the early 00’s.
I would say thusly: HTTP is an RPC protocol where the method name (or function or procedure name if you wish) is the method (sometimes called the verb). The URL path is the object that you are calling the method on. The arguments are query string + body as you say.
And sure I can say “please create a deletion for the element in this collection with id 1” it’s not wrong per se, but why wouldn’t I just say “please delete element 1”
because those are part of the HTTP spec and have reasonable meanings useful for implementing resource-oriented url schemes:
DELETE /comments/33
vs
POST /comments/33/delete
I agree that they aren’t really useful, but it takes very little effort for the author to add them and a lot of people want them.
Aside from the obviously minor difference of sending
POST /thing/delete
vsDELETE /thing
, other HTTP verbs can introduce additional overhead with CORS:- MDN: Cross-Origin Resource Sharing (CORS)
I was going to argue the opposite with approximately the very same line quoted. If you and your webapp rely on the browser for some of the protection against some level of cross-site request forgery attacks, you can use the verbs as they were intended and rely on the browser to enforce them to be usable according to CORS rules.
Guess why https://fetch.spec.whatwg.org/#forbidden-header-name lists the
X-HTTP-Method-Override
header (and friends) to forbidden headers in CORS? Lots of vulnerable web pages, that’s why :(CORS still works with GET and POST, it just doesn’t require multiple requests.
I disagree, they actually simplify things by disentangling POST from update and deletion actions.
Edit: in other words, they add a couple terms to our vocabulary…I don’t see how they add an entire layer.
layer is maybe a wrong term (i’m french)
i want to say that it add complexity: if you have a reverse proxy, it has to support the new verbs, if you have logs it should be aware of this verbs, if you have something in your infrastructure which used to ignore DELETE, and suddenly support it, it suddenly delete unwanted things
As a long time SPA apologist and licensed reverend of the church of tiny backends, I find this genuinely difficult to follow. What is “hypermedia” even? A tree with some implied semantics? How is that different than any other data? Why should I be constructing it on the backend (that place that knows comparatively nothing about the client)?
The back button has been solved for over a decade.
The complexity of “the backend has to care what things look like” is also enormous.
Theres talk of longevity and churn, but I’m pretty sure if I wrote
hx-target=...
in 2012, I would not get the desired effect.I haven’t managed state on a server beyond session cookies and auth in ages.
I saw a computer from 20 years ago use the internet just fine last weekend, and it needed some horrifying reverse proxy magic to make a secure connection, so “I’m using HTTPS” and “I’m supporting old hardware/OSs” is a contradiction anyway because decrypting HTTPS is more computationally intense than doom, and it’s also a moving target that we don’t get to pin. The end result is that if you can securely exchange information with a browser, it’s not ancient enough to need more than a few servings of polyfills to run a reasonably modern app.
React is the currently popular thing that makes stuff go vroom on the screen, so of course a lot of people make it more complicated than it needs to be, but like… remember early 2000s PHP CMSs? Those weren’t better, and if you did those wrong it was a security issue. At least a poorly written react UI can’t introduce a SQL injection.
To each their own, but I don’t get it 🤷♀️. I also don’t get how people end up with JS blobs bigger than a geocities rainbow divider gif, so maybe I’m just a loony.
Anything can be done wrong, and the fact that popular tools are used wrong often and obviously seems like a statistical inevitability, not a reason to try to popularize something different.
You must be using a different web than me.
Why would you prevent people to popularize anything that actually solves some problems? Isn’t having choice a good thing? I’m this author of this talk about a React->htmx move, and I’m completely freaked out by how many people have seen my talk, as if it was a major relief for the industry. I am also amazed, when hiring young developers, by how most of them don’t even know that sending HTML from the server is possible. Javascript-first web UI tools have become so hegemonic that we need to remind people that they have been invented to tackle certain kind of issues, and come with costs and trade-offs that some (many? most?) projects don’t have to bear. And that another way is possible.
Probably the statistics are way higher for technologies that carry a lot of complexity. Like I said in my talk, it’s very easy for JS programmers to feel overwhelmed by the complexity of their stack. Many companies have to pay for a very experienced developer, or several of them. And it’s becoming an impossible economical equation.
With htmx or other similar technologies, “what things look like” is obviously managed in the browser: that’s where CSS and JS run. Server-side web frameworks are amazingly equipped for more than a decade now to generate HTML pages and fragments very easily and serve them at high speed to the browser without the need of a JS intermediary.
I am shocked and stunned every single time I talk to someone who doesn’t know this. And if they are interested, I explain a little bit about how the web server can return any data, not just json.
Hypermedia encapsulates both current object state and valid operations on it in one partially machine-readable and partially user-readable structure.
A lobsters page, for example, lists the link and comments (the current state) and has a definition of how to comment: you can type in text and post it to the server. After you do that, the system replies with the updated state and possibly changed new valid operations. These are partially machine-readable - a generic program that understands HTML* can see it wants text to post to a particular server point - and partially user-readable, with layout and English text describing what it means and what it does.
Notice that this is all about information the backend applications knows: current data state and possible operations on it. It really has nothing to do with the client… which is part of why, when done well, it works on such a wide variety of clients.
To be fair, “the client” is a web page 9 out of 10 times so why abstract it away.
here you go:
https://hypermedia.systems
TLDR: hypermedia is a media, say, a text, with hypermedia controls in it. A lot more detail to be found in the book, or on the essays page:
https://htmx.org/essays
What kind of apps are better in HTMX vs. Rails Hotwire [1] or Phoenix Liveview [2] ? Honest question
The latter both aim to consolidate logic on the server side and reduce JavaScript, even more so than HTMX it seems
I’m not an experienced web dev, but I do know vanilla HTML, JS, CSS pretty well
I’m looking for some higher level abstractions to make an app, so I don’t have to re-invent the wheel.
A possible problem I see in HTMX is that it looks very “declarative” – and declarative systems are often convenient in the 80% case, often fall off a cliff for the other 20%. In my experience an app always needs “a bunch of special case code” somewhere – otherwise it wouldn’t be worth using/writing.
It seems like with Hotwire/Liveview the idea is that you have the full power of either Ruby or Elixir, which are general purpose languages.
Also, if you want to use less JavaScript, then HTMX is still seems like it must be a pretty big JavaScript library? Is it interpreting all the attributes and generating dynamic behavior in the browser?
Also being agnostic of the server side could also be a downside. That means you don’t have any real integration with what happens on the server?
[1] https://hotwired.dev/
[2] https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html
<hat>lieutenant maintainer of htmx</hat>
htmx and Hotwire are pretty similar, so it’s mostly a matter of preference which you use.
LiveView is quite different: instead of using HTTP and large-grain data exchange, it uses websockets and sends fine-grained updates. It’s basically a remote SPA. The downside is that you need to keep an Erlang process alive for each session, for the duration of the session. Erlang processes are famously very light and meant to be restarted when they crash, and as a result, this actually works.
htmx, on the other hand, is more of an extension to HTML (hence the name). Imagine the classic links-and-forms approach of building web apps, and then extend it:
These simple additions massively reduce the number of cases where JavaScript is needed.
Our experience agrees, in fact, we wrote a whole programming language aimes at a bunch of special-case code (see later). In our experience, events are the best way to glue JavaScript code together. htmx emits custom events for everything it does, and can use any native or custom event as well.
For writing your special-case code, there are a few solutions:
Again, Hotwire and htmx use very similar models, and Hotwire is actually backend agnostic as well. With htmx, you have the power of $FAVORITE_LANGUAGE .
“Integration” with server side can be useful, but it can also be problematic. It means the framework needs more control over your application. (see also: every npm package
foo
having a wrapper libraryreact-foo
). It also means the framework codebase has a network boundary cutting across it. (never try to abstract away a network boundary!)HTML is server-agnostic, and so is htmx
It’s about writing less JS rather than the amount shipped to the browser. Although 14kb min.gz is not that bad, no? (for reference, React seems to be around 44kb). We’re not trying to replace JavaScript, just the parts that should have been in HTML in the first place.
I’ll try to bring clarifications (I only know HTMX).
First off: HTMX and Hotwire are framework and language-agnostic, Liveview is not. That’s already a big deal! It is not “Rails” Hotwire (?)
AFAIK, Liveview is geared towards real-time changes, think reactive double-data binding à la . A Liveview connection lives on websockets, HTMX sends regular requests to the server.
In HTMX, there is no “double data binding”, but you can update and replace several parts of the DOM in one request. Like: clicking this button sends a GET to the server, it does its logic and returns 3 fragments of HTML for 3 distinct parts of the DOM: update the button, update the total showing at the top of the page, update a menu entry on the left (or whatever). All this, without writing JS, without a page reload.
So, it’s in the server? Or, as the author said, sometimes HTMX isn’t appropriate. If you want pure client-side reactivity, you’ll need a bit of JS. The options are many: a vanilla snippet, Alpine, or a JS framework.
With HTMX (and Hotwire IIUC) you get the full power of your language of choice. So I was able to add HTMX in my current Django or Lisp apps without any issue.
Not sure I understand the concern but I think you’re right: HTMX returns HTML fragments in order to update the DOM, not data in JSON that would inform a JS layer about the state of the server.
We are not talking about another neat library: https://unpoly.com/ Similar to HTMX, but (for the little I tried) it goes even further because it offers some widgets. For instance, you have two different static pages? Unpoly has a declarative way to turn one into a modal of the other.
HTMX is on my “things to try” list and I think its approach makes a lot of sense for many kinds of web apps. I love a lot of its design choices.
At the same time, I think the author neglects to mention some of the arguments against using it. The most obvious one: “Hey, can we make a mobile app too?” The React people will whip out React Native and reuse the server interaction code from the SPA. Their backend colleagues will barely have to do any work since it’s just another caller of the existing API. The server-rendered-HTML people, though, will scramble to design a native-app-friendly API from scratch and will be stuck maintaining two request-handling code paths to work with the same underlying data.
“We have several kinds of clients some of which aren’t web browsers” is a common enough scenario in my experience that I don’t think any HTML-centric approach is likely to be “the future” in the broad sense the post suggests. But it, or something like it, probably has a place in the future.
Maybe is it the goal of Hotewire’s Strada? (upcoming in 2023)
“This makes it easy to progressively level-up web interactions with native replacements.”
The “HTMX for mobile” seems to be Hyperview: https://hyperview.org/ (from the hypermedia.systems book)
“Hyperview is a new hypermedia format and React Native client for developing server-driven mobile apps.”
(it says “server-driven” and “networked mobile apps” and warns: “If your app relies on offline data or local computations, Hyperview won’t be the right choice.”)
I do agree that HTMX is all-in on the web, and it’s not suitable for native mobile apps. I have made a decent PWA with it, though, and compared to comparable SPAs it runs like greased lightning in a mobile browser.
That said, for a lot of things, you really could take the same approach as the article does for serving HTMX fragments vs full pages — check for an Accept: application/json header, return the appropriate JSON representation after doing the same logic you would for HTMX or no-JS. The client would have to be from scratch, yeah, you don’t get the benefits of something like React Native, but the backend still barely has to change.
I’d be really interested to hear more about a PWA in HTMX. Is the service worker very app-specific (like knowing how to render data to HTML) or more generic (like caching visited pages)? Do you end up duplicating logic between the server and service worker, or did you find a good way to divide it up? Or did you try to share the logic somehow?
For my app, it was pretty much just caching and serving some static internal pages. Since the service worker has to be in JS, I didn’t want to make it too involved. My main goals were just to make the app installable on a phone home screen, and to do something sensible when offline.
Do you consider media queries a insufficient approach to responsibility?
The author commented in this thread, literally three hours before you did, and linked to an essay he wrote about when not to use htmx.
That is the author of htmx, not the OP.
Haha, good point.
https://htmx.org/essays/when-to-use-hypermedia/
https://htmx.org/essays/splitting-your-apis/
It obviously depends on the app. HTMX is primarily targetting hypermedia not rich clients, so a mobile app is often not relevant. However, it would also not be a big deal to write a hypermedia client for mobile that was more limited/special case than a browser if you do need an app, and reuse the HTML descriptions etc without using a webview.
I don’t think it’s the future, but I definitely think it’s /a/ future. The way I see it, when you write an SPA-style front-end application, you take on the responsibility of writing the /entire/ application, where HTML and CSS are only used as graphics primitives, and you don’t/can’t rely on the browser for any functionality other than running your JS/Wasm VM. There are, certainly, web applications that require this — Infinite Mac being one of my favorites. But if you don’t want to, don’t need to, or can’t take on that effort, and want to leverage all the work that browser vendors have already done, HTMX is a better choice.
I’ve written several apps using HTMX and its predecessor, Intercooler.js, with either Django or ASP.NET MVC on the backend, and it’s always been a joy. One thing I’ve particularly appreciated is how it lets you really leverage the server-side templating libraries to use the same partial views in generating both full pages and HTMX responses.
How about PWA and offline apps?
How would you make something “live” like an animation or an interactive chart?
Security is often about limiting attack surface. With a REST/JSON approach, I can have an extremely limited number of powerful endpoints (like 20 for an entire large application, each tested, audited, profiled). In this case, I can imagine ending up with hundreds or thousands of endpoints. What does that mean for security? And if one endpoint is slow, then DDOSing will be a walk in the park.
Beyond that, this looks very cool.
How would you build something like this with htmx?
(A request scheduler for pages that make dozens or hundreds of network requests)
You probably wouldn’t write the request scheduler with HTMX, you’d just write it in Javascript.
And then how would you hook it into an application built with HTMX?
You would probably build it as an island of interactivity and then integrate it w/ the broader htmx application via events:
https://htmx.org/essays/when-to-use-hypermedia/#if-your-ui-state-is-updated-extremely-frequently
https://htmx.org/essays/hypermedia-friendly-scripting/
Lol, it depends how you wrote it.
hx-trigger
allows you to perform AJAX requests off of Javascript events, but I don’t know, I wouldn’t know how to correctly implement Datadog’s complex solution myself either.Probably not with native htmx, because there seems to be some smart-ass stuff there to linearize back-end requests.
But: one of the reasons these dashboards need to be optimized is that they are in charge of both requesting data and creating DOM nodes based on received data. If your architecture is hypermedia-oriented, the client app is only in charge of requesting HTML widgets from the server, and the HTML itself is rendered by… the browser, which does that in a pretty optimized way.
So maybe we’re talking about one of the few use cases where htmx wouldn’t do the trick, but I’m not sure the hypermedia approach wouldn’t be relevant. And we’re talking about a non-trivial use case of a company that has a huge tech team.