TLDR:如果你将 API 分成数据 API 和应用 API,如这里所述,你应该考虑将你的应用 API 从 JSON 更改为超媒体(HTML)并使用像 htmx 这样的超媒体导向库来获得超媒体模型的好处(简单性、可靠性、灵活性等)。
最近,Max Chernyak 写了一篇题为 不要构建通用 API 来为你的前端提供动力 的文章。他的 TLDR 是:
除非你在一个有联邦前端或 GraphQL 的大公司工作,否则 YAGNI。
然后他讨论了通用 API 和你的应用 API 的一些不同需求。他列出了以下内容作为通用 API 的需求:
并将这些作为应用 API 的需求:
我将这种需求的不一致称为数据/应用 API 阻抗不匹配问题。
Max 的建议是将 API 分成两个“半部分”:一个通用 API 和一个应用 API
我建议你停止将你的前端视为一个通用的 API 客户端,而开始将其视为应用程序的一部分。
想象一下,如果你可以只发送整个“页面”的 JSON 数据。为
/page/a
创建一个端点并渲染/page/a
的整个 JSON 数据。对每个页面都这样做。不要强迫你的前端开发者发送一堆单独的请求来渲染一个复杂的页面。停止用人为的限制来烦扰他们。让自己与服务器同步。
我完全同意 Max 对这个问题的看法。
我特别想强调的是,通用 API 需要稳定,而应用 API 必须快速变化以满足应用程序的需求。
Jean-Jacques Dubray 在这篇文章中描述了 API 设计师所面临的以下令人悲伤的现状:
我最近工作中最糟糕的部分是为前端开发者设计 API。对话不可避免地会变成这样:
开发者 - 那么,这个屏幕有数据元素 x、y、z… 你能创建一个响应格式为 {x: , y:, z: } 的 API 吗?
我 - 可以
这完美地概括了 Max 所注意到的紧张局势,即 API 工程师想要设计通用、稳定的 API,但却受制于快速变化的 UI 的摆布,这些 UI 有着复杂的数据需求,而这些需求通常最好在服务器端解决。
正如 Max 指出:
你可以让“页面 a”保持“简单”状态,只做它需要做的事情。你可以对“页面 a”进行严格的测试,以防范错误、安全问题和性能问题。你甚至可以将“页面 a”的所有内容在一个大的 SQL 查询中获取。
所以,我再次完全同意 Max 的观点,即存在数据/应用 API 阻抗不匹配问题,我赞赏他提出,与其转向像 GraphQL 这样的解决方案,不如将 API 分成两个。
然而,还有下一步要迈出。
一旦你将应用 API 从通用数据 API 中分离出来,你就不再受限于公共数据 API 的约束,并且可以自由地重新考虑该应用 API 的整体形式。我们可以用它做任何我们想做的事情,所以让我们在思考上扩展一点。
请注意,应用 API 的核心问题是快速变化和页面(或资源)特定的调整。事实证明,我们有一种非常好的技术可以处理完全这个问题:超媒体!
超媒体通过 HATEOAS 使 API 变化成为一个问题。当你在超媒体 API 中更改形状时,这很好:新 API 只会反映在服务器返回的新 HTML 中。你可以添加和修改端点,并且,瞧(在第一级近似中),你的客户端(即浏览器)不需要更新。
浏览器只是看到了新的 HTML,驱动它们的使用者会适当地对新功能做出反应.
所以,虽然我认为 Max 在正确的轨道上,但我认为他走得不够远:一旦你从心理上接受了通过将两者分离成不同的关注点来解决数据/应用 API 阻抗不匹配问题的想法,只需要再走一小段路,就能重新发现超媒体的优势。
你可能会反驳:“哦,但是超媒体应用程序不好用,我们不想回到 Web 1.0。”
这是一个非常合理的反对意见,但是人们一直在努力解决这个问题,现在已经有很多库可以解决在超媒体模型中 HTML 的可用性问题。
我最喜欢的两个是 unpoly,当然还有我自己的 htmx.
如果你切换到超媒体应用 API(这实际上只意味着“使用 HTML,就像以前一样”),那么你将获得 RESTful Web 模型的所有优势(简单性、可靠性等)以及成熟 Web 框架中的服务器端渲染的优势(缓存、SQL 优化等)。
并且,通过选择像 htmx 这样的超媒体导向的前端技术,你可以在该模型中创建出色的用户体验.
所有旧的东西都变成了新的,但这一次,它变得更好了一点。