Hypermedia Systems is a book written by Carson Gross, Adam Stepinski and Deniz Akşimşek.
It describes the benefits of creating hypermedia-driven applications.
Here are my notes and summary.
The road to Hypermedia Systems
Tim Berners-Lee used the term hypermedia in the first website in the world.
Clicking on a link allows to interact with the media in a manner beyond reading from start to end.
Browsers added the form element in the early 90s, standardized in HTML 2.0.
Hypermedia controls — links and forms — gave rise to a new way to build and distribute software based on the hypermedia notion.
In 2000, Roy Fielding further described this application architecture.
The book’s authors use the expression hypermedia system to describe a system architecture:
- whose building blocks are:
- hypertext/hypermedia (e.g. HTML, XML)
- network protocols (e.g. HTTP)
- servers
- clients (e.g. web browsers)
- adhering to the principles described by Roy Fielding
Rise of the SPA
In 2005, the XMLHttpRequest API became the key technology behind the Ajax revolution.
Ajax closed the gap between the experiences users can get from a desktop and a web application.
Richer applications became so large that people started building infrastructures to manage them.
These JavaScript Web Applications became known as SPAs (Single Page Applications).
SPAs have become the default in our industry:
- abandoning the notion of page
- moving to a JavaScript model living in memory
- exchanging micro transactions over JSON
Tight coupling of JSON APIs and UIs
SPAs interact with a server via JSON API calls.
The JavaScript must have intimate knowledge of the data to transform it into HTML:
- if the format of the returned JSON is modified
- then the UI code will almost always have to be modified
As a result, the API and the UI are tightly coupled.
And because the UI is constantly in flux, API endpoints will end up being always tweaked to please UI needs.
Your likely options will be API churn or GraphQL security-related issues.
The flexibility of Hypermedia APIs
An alternative approach consists of returning HTML responses.
| Response Type | HTML | JSON |
|---|---|---|
| Response |
|
|
| State of the application | Encoded in the response | Not encoded in the response |
| As state changes |
The browser needs to know:
|
The JavaScript needs to know:
|
So when a new feature is shipped:
- display and what can/cannot be done are self-contained in HTML responses
- the browser simply renders the new HTML (no extra documentation required)
- hypermedia APIs do not have the (breaking) changes headaches that JSON Data APIs do
The JSON response is smaller, but the flexibility of the HTML response is worth the trade-off.
This flexibility allows to build refactorable hypermedia APIs optimized to particular UI needs.
Extending HTML
Some JavaScript libraries have been returning HTML over the wire:
- Turbo (Hotwire), ex-Turbolinks (2012) inspired by PJAX (pushState and AJAX)
- htmx, ex-intercooler.js (2014)
- unpoly (2017)
- datastar (2024)
The main idea is to augment HTML by addressing its core limitations:
- allow any element to issue a request, not just
<a>and<form> - allow any event to trigger a request, not just
clickandsubmit - allow any HTTP method, not just
GETandPOST - allow any part of the screen to be replaceable (transclusion), not just the entire screen
Build sophisticated modern web applications
Augmenting HTML allows to reach a level of interactivity that most web developers would assume requires a SPA framework.
The book showcases this by using htmx to improve a Flask web application.
I developed a barebones Django version of it to experiment with htmx patterns:
- inline validation
- active search (hypermedia can scale)
- async and/or lazy loading (to solve performance issues)
- content updates anywhere on the screen (with CSS transitions)
- bulk actions
- server generated DOM events (using the DOM as an event bus)
- Server-Sent Events (it’s never been easier)
- etc.
Two things allow more readable/smaller code and prevent spaghetti code:
- htmx does not require to write JavaScript, which saves code and lowers the barriers to entry
- locality of behaviour is achieved by heavily relying on HTML attributes, which was once considered a bad practice
Other things to note:
- the code uses template inclusions rather than components
- htmx leaves room for progressive enhancement
- you can have one backend for many hypermedia formats
- you can leverage the cache behaviour of HTTP responses
The future could be even brighter.
Where do you want to spend your complexity budget?
Software systems are intrinsically more complex than physical systems and tend to be append-only.
RPC-like APIs and JS-heavy architectures add to that complexity:
- tooling (Webpack, Vite, Rollup, ESbuild, etc.)
- maintenance of a npm toolchain in parallel with a backend toolchain
- client-side routing
- new abstraction over DOM manipulation
- server-side HTML generation (or rendering)
- attaching dynamic behavior to server-rendered tags on load (hydration)
- scattering of components across multiple repositories
- performance issues
- frontend and backend teams disagreeing over JSON payload format
- etc.
When they’re a good fit, hypermedia concepts can simplify system architectures a lot.
You have to decide what matters and where you want to spend your complexity budget.