hypermedia essay

This commit is contained in:
carson 2021-06-17 10:16:31 -06:00
parent 5caf366449
commit c418bf52cf

View File

@ -0,0 +1,142 @@
---
layout: layout.njk
tags: posts
title: Hypermedia APIs vs. Data APIs
---
## Hypermedia APIs vs. Data APIs
A *hypermedia* API is an API that returns [hypermedia](https://en.wikipedia.org/wiki/Hypermedia), typically HTML over
HTTP. This style of API is distinguished from data-oriented APIs. These two categories have different design needs and
should be considered separately.
Hypermedia APIs:
* Will be [REST-ful](https://en.wikipedia.org/wiki/Representational_state_transfer) almost trivially
* Should be driven by the needs of the underlying hypermedia application
* May change dramatically without versioning information, because of the [self describing messages](https://en.wikipedia.org/wiki/Representational_state_transfer#Uniform_interface) inherent to the
* Should be passed directly to humans, to maximize the flexibility of the system
Data-Oriented APIs, on the other hand:
* Will not benefit dramatically from REST-fulness, beyond perhaps [Level 2 of the Richardson Maturity Model](https://en.wikipedia.org/wiki/Richardson_Maturity_Model)
* Should strive for regularity and expressivity due to the arbitrary data needs of consumers
* Should be versioned and very stable within a particular version
* Should be consumed by code, processed and then potentially presented to a human
## APIs Today
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 badly and to
little benefit of the end users.) There has been a [movement away](https://graphql.org/) from REST-ful APIs as the industry has begun
to [recognize the problems with fitting data APIs into the REST-ful model.](https://kieranpotts.com/rebranding-rest/)
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.
## Designing a Hypermedia API
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 [htmx discord](/discord) recently:
> 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.
Let's consider this UI in terms of a base url, `/contacts`
The first thing we will need is an end point to retrieve the form and the table of current contacts. This will
live at `/contacts`, giving:
```
GET /contacts -> render the form & contacts table
```
Next, we want to be able to create contacts. This would be done via a POST to the same URL:
```
GET /contacts -> render the form & contacts table
POST /contacts -> create the new contant, redirect to GET /contacts
```
with HTML that looks something like this:
```html
<div>
<form action='/contacts' method="post">
<!-- form for adding contacts -->
</form>
<table>
<!-- contacts table -->
</table>
</div>
```
So far, so standard web 1.0 application, and thus far the data-API and hypermedia API needs haven't diverged very much,
although note that the hypermedia API is *self describing* and could be modified (say, changing the URL for creating
contacts) without breaking the hypermedia application.
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, `/contacts/table`, which renders only the table of contacts:
```
GET /contacts -> render the form & contacts table
POST /contacts -> create the new contant, redirect to GET /contacts
GET /contacts/table -> render the contacts table
```
and then add a poll trigger to the table:
```html
<div>
<form action='/contacts' method="post">
<!-- form for adding contacts -->
</form>
<table hx-trigger="every 30s" hx-get="/contacts/table" hx-swap="outerHTML">
<!-- contacts table -->
</table>
</div>
```
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. It 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.
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:
```html
<div>
<form action='/contacts' method="post" hx-boost="true">
<!-- form for adding contacts -->
</form>
<table hx-trigger="every 30s" hx-get="/contacts/table" hx-swap="outerHTML">
<!-- contacts table -->
</table>
</div>
```
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 *hypermedia needs* rather than any sort of data model considerations:
we think in terms of what we are trying to achieve with our application.
## API Churn
The crux point of this essay is this: API churn is fine in a hypermedia system because *the messages in a hypermedia system are self-describing*.
We can thrash the API around and the application doesn't break: human users simply see the new hypermedia and select what
actions they want to do.
Humans, compared with computers, are [good at deciding what to do](https://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.html).
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. They also face pressure to provide higher levels of expressiveness so that they
can satisfy more client needs without modification.
*NB: This latter situation is especially dangerous when these data APIs are
consumed in a browser, because any data-api expressiveness you give to a front-end developer, you also are giving to
a potentially hostile user, who can fire up a console and begin hammering away at your API. Apparently, facebook uses
a [whitelist](https://twitter.com/AdamChainz/status/1392162996844212232) to deal with this. Do you?*
# Conclusion
When designing a hypermedia API, you should use a different design mindset than you use for data APIs. Churn is
less of a concern, and providing the end points you need for a good hypermedia experience should be your primary goal.