[译]为什么选用 Apollo:它的优点、缺点和备选方案

本文翻译自《React 学习之道》 原作者 Robin 的一片文章 https://www.robinwieruch.de/why-apollo-advantages-disadvantages-alternatives/

知乎连接

这篇包含两个部分,本文是它的第二部分。

Part 1:为什么选用 GraphQL:它的优点、缺点和备选方案


选择一个问题的正确解决方案并不简单。因为 GraphQL 是一个新兴的技术,GraphQL 时代里没有什么直接的答案,对于一个 GraphQL 支撑的 JavaScript 应用,很难寻找到对的方案。后面我会告诉你在 JavaScript 应用中使用 GraphQL 时,为什么应该或者不应该使用 Apollo,我不只想涉及好的方面,也要谈论不好地方。

在我们深入探讨 Apollo 的优点和缺点之前,我们先回答一个问题:什么是 Apollo?Apollo 似乎已让 GraphQL 在 JavaScript 能更加易用为目标。因为 GraphQL 是一们查询语言,并且有 JavaScript 的参考实现,Apollo 基于这点,构建了自己的一套生态,让 GraphQL 使用更加简单,降低了使用门槛。这既包含客户端,也包含了服务端,他们为两端都构建了大量的类库生态。他们甚至提供一个中介层,作为 GraphQL 网关(gateway)。因此如果你对在 JavaScript 应用中使用 GraphQL 有兴趣的话,那么 Apollo 和它的周边生态是一个很好的选择。

Apollo 的优点

下面的话题我会展示使用 Apollo 的主要优点

Apollo 的生态

Apollo 的生态提供很多问题的解决方案,即使在使用 GraphQL 早期的时候。并且这个生态还在壮大中。在每个技术大会上,该公司都会宣布 Apollo 的更新或者某个类库可以作为 Apollo 技术栈的补充。比方说,这就是为什么 Apollo 不仅支持了 GraphQL,也通过向后兼容性特性支持了 RESTful 架构。它不仅基于 GraphQL 使用网络层来获取远端数据,也提供了本地数据的状态管理解决方案。因此你决定在应用中使用 Apollo,欢迎来到一个精彩的生态系统中来。

Apollo 后的公司和社区

Apollo 后的公司(Meteor Development Group Inc.)为之花费了很多资源和精力。他们积极参与开源建设,为他们的产品书写了很多文章,并且精彩能在各个技术大会上看到他们。总之,GraphQL 生态看起来有个不错的未来(https://techcrunch.com/2018/05/15/prisma/)。很多人为之演说,并在他们自己的应用中使用。此外,即便 Apollo 是由它的公司支持着,背后的社区也在壮大中。更多的人采用了 GraphQL 并选择 Apollo 加入到他们的服务端和客户端程序中。

谁在使用 Apollo?

有很多流行的和精通技术的公司已经在使用 Apollo。不只是 Apollo 公司(之前开发了流行的 Meteor 框架)自个在用,并且还有诸如 Airbnb 和 Twitch 在使用着。下面是一份在他们的 JavaScript 应用中使用了 Apollo 的公司列表:

Apollo 的文档

虽然 Apollo 一直都在演进,背后的团队和社区都一直确保文档保持更新。通过他们的文档,你可以获得如何搭建第一个 Apollo 的应用的知识,而不需要依赖第三方的资源。文档涵盖了非常多的领域,可能对一个新手来说有点不知所措。因此,请确保按内容主题阅读,并运用到你的应用中去。

Apollo 的类库

Apollo 提供了许多完美的 GraphQL 技术栈。他们用某种方式开源了这些类库,以便这些类库可以被组合和替换。

比方说,前者可能看到 Apollo Link 提供了了 API 来将不同的特性链接到 GraphQL 的控制流中。它可以启用网络断开自动重试,或者使用一个 RESTful API 端点 而不是 GraphQL 端点(两者也可以一起使用)。

后者是说,Apollo 提供了可替换的类库,比方说,看看 Apollo 的客户缓存。Apollo 客户端本身不关心缓存数据存储的地方。你可以使用由 Apollo 提供的缓存库,或者使用社区提供的。这就是设置 Apollo 实例后,就已经有了一些缓存的原因。

Apollo 的特性

Apollo 有许多内建特性,如果你单独实现的话,实现起来并不简单。因此你可以不用在应用中考虑这些特性的复杂性,将客户端与服务端部分的交互交给 Apollo 就好了。比方说,Apollo 客户端会确保缓存你的请求(当已经存在缓存时,不会重新发起请求),这很能提升应用的性能,因为节省了宝贵的网络交通资源。此外,Apollo 会归一化(normalize)你的数据,当通过一个 GraphQL 查询来请求一个嵌套结构的数据时,数据会以一种归一过的数据结构存储在客户端缓存中。因此,你可以通过一个标识符直接从 Apollo 客户端缓存中读取数据,比方说,不需要哎一个“作者”实体中查询一篇”文章“。文章本身会通过一个标识符在 Apollo 客户端换做中检索。除了缓存和归一化,Apollo 还有很多特性,比如错误管理、分页支持以及 UI 优化和预读取数据、绑定数据层(Apollo 客户端)与视图层(比如React)。

与其他框架的交互

Apollo 其中一个库,运行将 Apollo 客户端与 React 进行绑定,就像流行的其他类库(Redux、Mobx 等等)做的一样。react-apollo 库会提高一个高阶组件(和一个渲染 prop 的组件)帮助建立两者的连接。然而,并不只是建立了 Apollo 到 React 连接的类库,其他一些类库也能处理 Apollo 到 Angular 或者 Apollo 到 Vue 的连接。这让 Apollo 客户端无需关心视图层,这对它的生态发展很有好处。

Apollo 不只是关心客户端的类库,它也为 Nodejs 服务端提供了多套解决方案,来连接不同的 Nodejs 库。Express 版本的 Apollo Server 是开发者和公司中最普遍的的选择,不过也存在其他版本的 Apollo Server 解决方案 Koa、Hapi。

GraphQL 和 Apollo 的状态管理

随着 JavaScript 应用中出现 GraphQL,状态管理再次进入了一个混乱状态。尽管在您的应用程序中使用诸如 Apollo Client之 类的 GraphQL 库,因为它负责处理远程数据的所有状态管理,可以消除许多痛点,不过,人们会困惑在哪里安放如 Redux 或 MobX 之类的状态管理库。不过,可以很简单地用 Redux 或者 Mobx 管理本地数据,将远端数据留给 Apollo。不需要在 Redux 中关系如何异步获取数据,Apollo 客户端会处理的。这样 Redux 就成了一个可预测应用状态(本地数据/视图层数据/ UI 数据等等)的状态容器。也许甚至你都需要 Redux,因为你的应用状态并没有复杂到需要 Redux 来管理,不过最好还是被 React 的本地状态管理机制管理起来。

同时,Apollo 已经发布了它的本地状态管理方案(本来应该被 React 本地 State 、 Redux 或者 Mobx 来管理的),拥抱 GraphQL 的一切。Apollo Link State 库允许你不止在 Apollo 客户端使用 GraphQL 操作,还可以管理本地数据。这就是 Apollo 所说的:”嘿,你根本不需要其他的状态管理库,我们会照顾好你的数据的。”这也是 JavaScript 开发中,又一个激动人心的时刻。

便利的开发体验

使用 Apollo 的开发 JavaScript 应用的每一天都变得更好。其他人发布的工具也帮助你更好的开发这些应用。这些开发工具包括浏览器扩展、像 GraphiQL 这种第三方工具可以执行 GraphQL 操作、以及其他简化 Apollo 应用开发的的类库。比方说,Apollo Boost 库让你可以设置 Apollo 客户端时几乎是零配置,快速开始开发 GraphQL 客户端应用。大体上,Apollo 帮你省去了使用 GraphQL 的 JavaScript 参考实现时的各种样板代码。

Apollo 的缺点

下面的话题我们会列出一些使用 Apollo 的缺点。并不是我意图挑 Apollo 的刺,我自己就很喜欢使用 Apollo,但是我想给你的一个使用 Apollo 全面的参考。如果你觉得这个部分有改进或商榷的空间,或者其他部分有,请联系我。

过于前卫(Bleeding Edge)

因为 GraphQL 也处于初期发展的阶段,不只是 Apollo,其他每个早期的使用者,都工作在前沿科技上探索。Apollo 团队急切希望基于 GraphQL 构建一个丰富的生态,不只提供一些基础特性,还想提供一些像缓存和监控这些高级特性。

不过,这也导致一切都,不稳定。特别是因为 Apollo 发展地如此迅速,你将来可能需要更新 GraphQL 相关的一些类库。不过 Apollo 团队尽力保持最小化 Break Change。相对而言,其他一些 GraphQL 库可能会更加稳定,不过也没有 Apollo 提供很多强大特性。

另外一方面,当一切都飞速演化时,学习体验就会受到影响。比方说,通常 GraphQL 和 Apollo 的教程刚好过时了,你不得不寻找其他学习资源。但是,这个情况并不仅只是 Apollo 有,这个领域的其他开源项目也有,通常编程语言教程里也有。

正在施工(Under Construction)

Apollo 团队和社区急切于在快节奏下实现很多新的特性。不过走的快也总是带有某种代价。比如,当搜寻一个问题的解决方案时,你经常会找到一个 Github Issue,因为关于这个问题没有其他的信息了。毕竟,你很可能就碰到一些坑,不过即使你在 Github Issue 找到你的问题,可能也没有相应问题的解决方案。

发展过快总是会以疏忽旧事物为代价。如我提到的,当 Apollo 废弃使用 Redux 时,人们似乎非常不理解。Apollo 不认为 Redux 适合搭配使用,因为它已经作为内部状态管理方案被废弃了,许多人在 Apollo 2.0 发布的时候不知道怎么处理这个新消息。我认为 Apollo 背后的团队一下子定了太多目标了,他们奋力保持跟上 GraphQL 生态的快节奏,在开源的世界里,听取所有的意见并不容易。所有说,这也是你来帮助共享他们的开源类库的机会了。

大胆和时尚

Apollo 非常大胆,它已经超越了 GraphQL。他们仅是 JavaScript 中使用 GraphQL 连接客户端和服务端的网络层生态,他们还将他们定位为未来的数据管理解决方案。他们不仅使用 GraphQL 连接你的客户端和服务端,还提供了其他如 apollo-link-rest 应对 RESTful API 以及 apollo-link-state 应对不呢度状态管理。许多人喜欢这套基于他们技术栈的新解决方案,不过其他人怀疑这是“GraphQL 一切”思想作祟。毕竟,这取决于人民是否想要“GraphQL 一切”咯。

Apollo 非常时髦,因为它一直保持紧跟趋势。在 React 中,最新的趋势是 render prop 组件。因为 render prop 组件比高阶组件有些有待探讨的优势,React Apollo 库就在高阶组件旁边,引入了 render prop 组件。不过提供了多套解决方案这点非常厉害,因为两套概念,高阶组件和 render props 组件,有着各自的优点和缺点。不过,Apollo 相比高阶组件更提倡 render props 组件,不是很清楚是因为基于炒作的带动还是基于营销的需求,或者是他们真的认为这是未来更好的开发方式。render props 在 React 都是相当新的概念,还需要人们花费时间理解它的缺点(对比高级组件)。个人经历来说,我已经看到一个 React 组件因为使用多个 render props 组件,变得非常冗长,及时某一个 prop 不需要使用渲染 prop 函数,还不如使用高级组件的方式重新写到这个组件中去。不过,Apollo 同时提供了两种方式,开发者可以根据具体的选型选择使用哪一种标准应用到他们的应用程序中,毕竟没有银弹。Apollo 也一直保持与其他类库的更新趋势。他们并不只局限在他们的世界中,他们也积极与其他有关 Apollo 生态的类库的开发者们沟通着。

缺乏竞争

个人而言,之前所有都关注在 GraphQL 的最前沿。这些问题也同样适用这个领域的其他开源方案。然后,对我而言,担心的是,在 JavaScript 的 GraphQL 领域中,Apollo 缺乏竞争。一些 Apollo 的替代方案可以在下个部分找到,不过它们相比 Apollo 的生态而言,都没有那么流行和强大。虽然你也可以做一个自己的 GraphQL 客户端类库,不过不是每一人都要从这个地方开始。虽然 Apollo 解决的问题可能根本不重要,不过我觉得在 JavaScript 的 GraphQL 生态中引入竞争会更好。我相信现在在 GraphQL 的领域里还存在巨大的发展潜力,任何开源开发着都值得来尝试。

JavaScript、React 和 Node.js 中 Apollo 的替代方案

许多上面列举的缺点都是因为 GraphQL 作为 RESTful 驱动架构替代方案的早期发展的原因。这里有一些 Apollo 客户端和 Apollo 服务端的备选方案,你可以用来在 JavaScript 中暴露或者消费 GraphQL API。下面列举了 JavaScript 生态中,在 React 客户端和 Node.js 中的一些方案供参考。

React 中 Apollo 客户端替代方案

当谈到 React、Angular 或者其他 Apollo 客户端时,有一些方案可供你参考。明显这里没有列举他们的优缺点。

  • 普通的 HTTP 请求:即便存在成熟的 GraphQL 类库来执行 GraphQL 操作,GraphQL 本身并不关心网络层,所以你可以使用普通的 HTTP 方法带上具有 GraphQL 查询和修改的结构内容对单断点进行操作。
  • Relay: Relay 是 Facebook 为在 React 客户端应用中消费 GraphQL 的类库,是所有 GraphQL 客户端类库中最先出现的,还在 Apollo 出现之前。
  • urql:urql 是一个来自 Formidable Labs 的 GraphQL 客户端类库,用来在 React 中消费 GraphQL。与不断增长的 Apollo 巨兽相比,它是开源的简约替代品。
  • AWS Amplify - GraphQL 客户端: AWS Amplify 为云应用提供了多个类库。其中一个模块就是 GraphQL 客户端,它可以用在通常的 GraphQL 服务器或者 AWS 的 AppSync API 上。

Apollo 服务端的 Node.js 备选方案

当谈到 Apollo 服务端 的 Express、Koa、Hapi 等等实现时,有这么一些替代方案供选择。明显这也没有猎取他们本身的优缺点。

  • express-graphql:这个库提供了暴露你的 GraphQL 层到 Express 中间件的底层 API。它使用 GraphQL.js 参考实现来定义你的 GraphQL schema。

不过,还是有很多理由使用 Apollo 和它强大的生态。可以在 JavaScript 应用中可以通过 GraphQL 接口操作 RESTful 接口。他们的类库是框架无关的,因此可以被应用到多个客户端框架(React、Angular、Vue)和服务端(Express、Koa、Hapi)中去。

扩展阅读:一份完整的 React、 Apollo 和 GraphQL 教程