为什么 Webdevs 一直试图消灭 REST?

2025-05-27

为什么 Webdevs 一直试图消灭 REST?

翻译:俄语

替代文本

编辑此图表

通过观察客户端-服务器范例的最新趋势,从 Apollo GraphQL 到 React Server Components 再到 Rails Hotwire,我有了一个启示,它帮助我理解这一切:它们都是基于 REST 的抽象!

有两种观点:

  • 智能客户端:状态更新首先在客户端呈现,然后发送回服务器。
    • 您可以自己动手:使用状态管理解决方案(如ReduxSvelte Stores)并手写客户端-服务器协调逻辑的每一部分。
    • 您可以使用结合状态和数据获取的库Apollo ClientReact QueryRxDBGunDBWatermelonDBAbsurd-SQL都执行获取数据和存储相关状态的双重工作。(如果进行评估,您可以在此处查看并行实现
    • 你可以使用抽象框架:Blitz.jsNext.js
    • 或者你可以将其从货架上拿下来Google 的 FirebaseAWS 的 Amplify/AppSync完全由供应商提供,并与身份验证、数据库和存储等后端资源垂直集成(可以说是之前的MongoDB Realm和 Meteor 的minimongo )
  • 智能服务器:状态更新首先发送到服务器,然后服务器将重新渲染发送到客户端(无论是 HTML 块、序列化的 React 组件还是 XML)。

当然,“智能服务器”范式并非全新概念。它有一个历史前身——我们姑且称之为“传统服务器”范式。Wordpress、Django、Laravel 之类的框架会填充 HTML 模板,浏览器的唯一工作就是渲染它们并发送后续请求。我们逐渐摒弃了这些框架,转而使用客户端 JS(即 AJAX)来提供更持久的交互体验。很长一段时间以来,我们只满足于从客户端 ping REST 端点,以确保前端和后端之间的关注点清晰分离。

那么,我们为什么要打破旧的客户端-服务器模式呢?哪一方会胜出?

关乎用户体验

讽刺的是,双方在用户体验方面有着截然不同的目标,并且可能会认为对方的性能较差。

  • 智能客户端支持离线优先应用程序和乐观更新,因此您的应用程序可以在没有互联网的情况下继续工作,并且感觉即时,因为您正在对远程数据的本地缓存进行 CRUD(我在乐观的离线优先应用程序中写过这方面的内容,RxDB在这里有一个很好的描述)。
    • 这提高了应用程序的感知性能
    • 然而它们的缺点是往往会预先带来很大的 JS 包:Firebase 会给你的包增加多达 1mb,Amplify 经过大量的模块化工作后将其减少到 230kb,Realm 则为 42kb。
  • 智能服务器通过在服务器端而不是客户端执行工作来直接减轻 JS 的负担,同时无缝地修补更新,就像在客户端完成一样。Facebook 报告称,捆绑包减少了高达29%
    • 这提高了网站的首次加载性能并减少了整个会话中发送的 JavaScript 总量。
    • 然而,它们的缺点是,每个用户都在你的服务器上进行渲染,而不是在他们的浏览器上。这必然会占用更多资源,并且每次用户交互都会产生一次完整的网络往返。如果能够在边缘自动扩展计算和存储(例如,使用Cloudflare WorkersAWS Lambda上的无服务器渲染),这个问题就可以得到缓解。此外,还存在一些实际的安全问题,这些问题应该会随着时间的推移得到解决。

如果有的话,这里的“赢家”将取决于用例 - 如果您正在编写一个 Web 应用程序,其中用户会感觉到任何响应延迟,那么您需要智能客户端方法,但如果您正在编写一个电子商务网站,那么您对速度的需求将有利于智能服务器。

这是关于开发者体验

  • 平台 SDK。对于 Firebase 和 AWS Amplify 等前端平台即服务供应商来说,他们的客户端显然只是平台 SDK——由于他们完全了解你的后端,因此他们可以使用惯用语言 SDK 在前端为你提供更好的 DX。
  • 减少样板。您无需经历编写后端处理程序/解析器,然后编写相应的前端 API 调用/乐观更新的两阶段过程,而是可以只编写一次后端,然后生成自定义客户端的代码,或者在前端提供类似直接数据库操作的功能(带有授权和同步规则)。

    • 智能服务器的样板代码大幅减少,因为同步协议消除了所有协调客户端-服务器交互的需要。一位 LiveView 用户的评论

    LiveView 简直太棒了。这是我自 Rails v1 以来在 Web 开发中经历的最大变革。现在,我无需编写任何 JavaScript 代码,就能构建出内容丰富、互动性强的游戏。它能够处理复杂的服务器/API/前端构建项目,只需十分之一的代码量就能达到同样的效果。

  • 离线。Firebase Firestore 和 Amplify AppSync 都支持离线持久化。由于它们了解您的数据库模式,因此可以轻松提供本地副本和冲突解决。此外,还有一些与供应商无关的替代方案,例如RxDBRedux Offline,但需要更多粘合工作。

    • 离线优先要求您拥有数据的本地副本,这意味着对本地副本进行 CRUD 会更加简单(见下文)。
  • 减少乐观更新的样板

    • 当你进行正常的乐观更新时,你必须做 4 件事:
      1. 向服务器发送更新,
      2. 乐观地更新本地状态,
      3. 在服务器成功后完成乐观更新,
      4. 服务器失败时撤消乐观更新
    • 使用本地数据库副本,您只需做一件事:将更新写入本地数据库并等待其同步。本地数据库应该公开更新状态(您可以在 UI 中反映),并允许您集中处理故障。
  • 人员。这是一个组织层面的争论,而非技术层面的争论。你的前端开发人员有多少次因为某些事情“被后端阻碍”,不得不等待 2-3 个冲刺才能等到其他人交付他们需要的东西?这极大地扰乱了工作流程。赋予开发人员全栈访问权限,让他们能够访问交付功能所需的一切,无论是无服务器函数、数据库访问还是其他什么。智能客户端/服务器既能解决用户体验问题,也能解决人员问题。

    • 这就是为什么我大力倡导将行业界限从“前端 vs 后端”转变为“产品 vs 平台”。Chris Coyier 对此的称呼是“全能的前端开发者”
    • GraphQL 也是一种秘密的“人力技术”,因为它将前端数据需求与有限的后端端点集分离。

智能客户端和智能服务器都极大地改善了 DX 的所有这些方面。

这是关于协议的

更好的协议可以提升用户体验(消除用户面临的错误并提供更快的更新)和用户体验(将错误信息左移),它们与“为什么要避免使用 REST”的争论息息相关,所以我将它们单独归类。当然,从技术上讲,你使用的任何协议都可能只是 REST 之上的一层——如果你有一个单独的层(例如CRDTs)来处理同步/冲突解决,那么你真正使用的就是 REST 协议。

其中很多评论都会涉及 GraphQL,因为它是我最熟悉的非 REST 协议;但请随时告诉我其他协议可能适用或不同的方面。

  • 类型安全: GraphQL在运行时验证每个请求。trpc在编译时执行此操作。
    • 增加类型注释可以更好地生成客户端 SDK 的代码,而无需手动编写。这在 gRPC 中比在 GraphQL 中更为成熟,我不确定为什么。
  • 带宽:通过网络发送更少的数据(或以改善用户体验的格式发送数据)
    • GraphQL 有助于解决过度获取问题。实际上,我认为除非你是 Facebook 或 Airbnb,否则它的重要性被夸大了。然而,持久化查询对于解决上传带宽问题的实用性却被低估了。
    • Hotwire通过网络发送文字 HTML
    • React 服务器组件通过网络发送序列化的组件数据;由于可以采用 React,因此更加紧凑,并且能够与屏幕上的加载状态顺利协调
  • 实时:在网络上提供“现场”和“协作”体验
    • 这可以通过定期轮询和长轮询来实现,但像 UDP、WebRTC 和 WebSockets 这样的更原生的协议可能是更好的解决方案
    • Replicache(用于Next.js Live)和Croquet在这里看起来很有趣
    • UDP 本身似乎是一个成熟的基础,可以进行更多的协议创新;甚至HTTP/3也将建立在其之上

我认为还有一些有待改进的领域尚未得到充分解答:

  • 性能:每个后端开发人员的噩梦之一就是在不知不觉中让特定用户发起可能阻塞系统资源的昂贵查询。GraphQL 的复杂性预算问题尚未得到解决。这是一个棘手的话题,但新的协议至少可以在性能和灵活性之间开启一条更有趣的平衡之道。
  • 安全性:允许前端开发人员直接访问数据库需要更多安全防护措施。集成身份验证解决方案的供应商可以提供一定帮助,但新协议的倡导者需要像宣传其对开发人员体验的益处一样,大力宣传其安全需求。

并非所有人都反对 REST

是的,我的标题确实有点标题党;REST 对绝大多数 Web 开发者来说完全没问题。甚至有人在 REST 范式中不断突破界限。


后续行动

过渡应用程序

Rich Harris 最近在 Jamstack 会议上发表了主题演讲,阐述了他对这个问题的看法(TLDR 在此处):

读者反馈

  • Jonathan W:“这个问题的框架让我的思绪有些混乱。整个情况感觉非常类似于开发人员第一次意识到对象关系阻抗不匹配——当你在业务领域之上,将应用程序框架置于对象关系映射 (ORM) 之上,ORM 之上,RDBMS 之上,RDBMS 之上时,所有细微的差别就开始显现出来(你知道,这是一个很重要的话题)。每一层抽象本身都是可以接受的,但其影响会在每个层面上随着时间的推移而累积。”
  • @thxdr:其他值得探索的格式:JSONAPI是 JSON REST 规范,而Relay 规范本质上是 GraphQL 超集规范
文章来源:https://dev.to/swyx/why-do-webdevs-keep-trying-to-kill-rest-j2j
PREV
TurboRepo 为何将成为 2022 年的第一大趋势
NEXT
Svelte 用于网站,React 用于应用程序