超媒体 API 与数据 API

Carson Gross

一个超媒体 API 是一个返回超媒体的 API,通常是通过 HTTP 返回 HTML。这种 API 风格区别于不返回超媒体的数据 API。今天,这种后一种 API 风格最常见的形式是无处不在的 JSON API。

这两种不同的 API 类型具有截然不同的设计需求,因此在创建时应使用不同的设计约束并采用不同的目标。

超媒体 API

另一方面,数据 API

#当今的 API

如今,API 通常被认为是 JSON-over-HTTP。这些几乎总是数据导向的 API 而不是超媒体 API,尽管偶尔会将超媒体概念合并到其中(通常对最终用户几乎没有益处)。随着行业开始认识到将数据 API 融入 RESTful 模型的问题,已经出现了一种远离 RESTful API 的趋势

这是一件好事:行业应该在数据 API 世界中质疑 RESTful 的理念,并开始关注过去那些做得更好的客户端-服务器技术,这些技术更好地服务于特定的网络架构,而将 REST 留给它被创造出来描述的网络架构:超媒体 API。

#设计超媒体 API

为了展示超媒体 API 的设计方式可能与数据 API 不同,让我们考虑以下情况,这种情况最近在htmx discord 上出现

我想要一个页面,上面有表单和表格。表单将向表格添加新元素,表格也将每 30 秒轮询一次,以便显示来自其他用户的更新。

让我们从基准 URL /contacts 来考虑这个 UI

首先,我们需要一个端点来检索表单和当前联系人的表格。这将位于 /contacts,给出

  GET /contacts -> render the form & contacts table

接下来,我们希望能够创建联系人。这可以通过向同一个 URL 发送 POST 请求来完成

  GET /contacts -> render the form & contacts table
  POST /contacts -> create the new contact, redirect to GET /contacts

HTML 代码如下

<div>
    <form action='/contacts' method="post">
      <!-- form for adding contacts -->
    </form>
    <table>
      <!-- contacts table -->
    </table>
</div>

到目前为止,这是标准的 Web 1.0 应用程序,到目前为止,数据 API 和超媒体 API 的需求并没有太大区别,尽管值得注意的是,超媒体 API 是自描述的,可以进行修改(例如,更改创建联系人的 URL),而不会破坏超媒体应用程序。

现在我们进入需要 htmx 的部分:偶尔轮询服务器以获取表格的更新。为此,我们将添加一个新端点 /contacts/table,该端点仅呈现联系人表格

  GET /contacts -> render the form & contacts table
  POST /contacts -> create the new contact, redirect to GET /contacts
  GET /contacts/table -> render the contacts table

然后向表格添加轮询触发器

<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>

在这里,我们看到超媒体 API 和数据 API 开始出现分歧。这个新端点完全由超媒体需求驱动,而不是数据模型需求。如果应用程序的超媒体需求发生变化,这个端点可以消失;它的形式可能会发生巨大的变化等等,这完全是可以接受的,因为系统是自描述的。

由于我们已经更新了 HTML 以使用 htmx 进行轮询,我们不妨也让表单使用 htmx 来获得更好的用户体验

<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>

如果我们愿意,可以为诸如输入服务器端验证、动态表单等添加额外的端点。这些端点将由超媒体需求驱动,而不是任何数据模型考虑因素:我们从应用程序要实现的目标角度思考。

#API 变化

这篇短文的要点是:API 变化在超媒体系统中是可以的,因为超媒体系统中的消息是自描述的。我们可以围绕 API 进行更改,而应用程序不会崩溃:人类用户只需看到新的超媒体(HTML)并选择他们想要执行的操作。

与计算机相比,人类擅长决定做什么,并且对变化能够适度地接受。

这与数据 API 形成对比。数据 API 无法在不破坏客户端代码的情况下进行修改,因此在进行更改时必须更加自律。数据 API 还面临着提供更高水平的表现力的压力,以便能够满足更多客户端需求而无需修改。

#结论

在设计超媒体 API 时,你应该使用与数据 API 不同的设计思路。变化不再是主要问题,提供实现良好超媒体体验所需的端点应该是你的主要目标。

</>