GraphQL 与 REST:两种 API 架构
GraphQL
既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。GraphQL
对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
在过去十年中,REST
已经成为 Web API 的设计标准,提供了一些很棒的想法,例如无状态服务器和对资源的结构化访问。但是,REST
API 已经显示出太不灵活,无法满足访问客户端快速变化的需求。
GraphQL
的开发是为了满足更高灵活性和效率的需求!它解决了开发人员在与REST
API 交互时遇到的许多缺点和低效问题。
REST
和GraphQL
区别
为了说明从 API 获取数据时 REST 和 GraphQL 之间的主要区别,让我们考虑一个简单的示例场景:在博客应用程序中,应用程序需要显示特定用户的帖子标题。同时还显示该用户的最后 3 个关注者的姓名。
如何通过 REST 和 GraphQL 解决这种情况?
使用 REST 与 GraphQL 进行数据获取
使用REST
API,需要设计三个接口来获取数据:
/users/<id>
:获取初始用户数据/users/<id>/posts
: 返回用户的所有帖子/users/<id>/followers
:返回每个用户的关注者列表。
在GraphQL
中只需向GraphQL
服务器发送一个包含具体数据要求的查询。然后,服务器使用 JSON 对象进行响应,满足需求。
使用 GraphQL,客户端可以准确指定查询中所需的数据属性。
REST
REST
是最通用,也是最常用的接口设计方案,它是无状态的,以资源为核心,针对如何操作资源定义了一系列 URL 约定,而操作类型通过 GET
POST
PUT
DELETE
等 HTTP Methods 表示。
下载多余的数据
客户端下载的信息量超过了应用程序中实际需要的信息量。例如一个页面,只需要显示一个用户名列表。在
REST
API 中,此应用程序通常会命中/users
接收带有用户数据的 JSON 数组,为了通用性,该接口可能返回更多的用户信息,如生日或者地址。信息缺失和 N+1 问题
信息缺失通常意味着特定接口不能提供足够的所需信息。客户端需要提出额外的接口来获取所需要的信息。
GraphQL
GraphQL
不是 REST
的替代品,而是另一种交互形式:前端决定后端的返回结果。
GraphQL
API 的主要应用场景是 API 网关,在客户端和服务之间提供了一个抽象层。
GraphQL
带来的最大好处是精简请求响应内容,不会出现冗余字段,前端可以决定后端返回什么数据。但要注意的是,前端的决定权取决于后端支持什么数据,因此 GraphQL
更像是精简了返回值的 REST
,而后端接口也可以一次性定义完所有功能,而不需要逐个开发。现在来说说GraphQL
带来的好处:
提高开发速度
首先,
GraphQL
有助于减少请求数。通过单个调用来获取所需的数据比使用多个请求要容易得多。从开发的角度来看,这加快了开发速度。后端和客户端团队需要通过密切合作来定义 API、测试,并做出更改。前端、移动、物联网等客户端团队不断迭代功能,并尝试使用新的 UX 和设计。数据需求经常会发生变化,后端团队必须跟上节奏。如果客户端和后端代码由同一团队负责,那么问题就没那么严重了。
使用
GraphQL
,客户端工程师可以完全控制前端,不需要依赖任何人,因为可以使用GraphQL
查询告诉后端他们需要什么以及响应结构应该是怎样的。而不需要花时间让后端 API 团队添加或修改某些内容。GraphQL
具有自文档的特点,可以节省一些用于查找文档以便了解如何使用 API 的时间。当拥有大量
GraphQL
API 后,然后有人想出了一个新的产品创意,使用已有的GraphQL
API 可以快速实现原型,比调用各种 REST API 或为新应用程序构建新的 REST API 要快得多。提升性能
工程师并不是唯一从
GraphQL
中受益的人。用户也会从中受益,因为应用程序的性能获得了提升(可以感知到的):减少了有效载荷(客户端只需要必要的东西)
多个请求合并为一个请求可减少网络开销;
更快的 UI 更新
改进的安全性、强类型和验证
GraphQL
的 schema 与语言无关。对前面的示例进行扩展,我们可以在 schema 中定义 Address 类型:type Address { city: String! country: String! zip: Int }
String 和 Int 是标量类型,! 表示字段不可为空。
schema 验证是 GraphQL 规范的一部分,因此像这样的查询将返回错误,因为 name 和 phone 不是 Address 对象的字段:
{ user (id: 123) { address { name phone } } }
GraphQL 的实现
在选择实现 GraphQL API 的平台时,Node 是一个候选项,因为最初 GraphQL 用于 Web 应用程序和前端,而 Node 是开发 Web 应用程序的首选,因为它是基于 JavaScript 的。使用 Node 可以非常容易地实现 GraphQL(假设提供了 schema)。事实上,使用 Express 或 Koa 来实现只需要几行代码:
schema 是使用 npm 的 graphql 中的类型来定义的。Query 和 Mutation 是特殊的 schema 类型。
GraphQL API 的大部分实现都在于 schema 和解析器。解析器可以包含任意代码,但最常见的是以下五个主要类别:
调用 Thrift、gRPC 或其他 RPC 服务;
调用 HTTP REST API(当优先事项不是重写现有 REST API 时);
直接调用数据存储;
调用其他 GraphQL schema 查询或服务;
调用外部 API。
GraphQL 不一定需要客户端。一个简单的 GraphQL 请求就是一个常规的 POST HTTP 请求,其中包含了查询内容。我们可以使用任意的 HTTP 代理库(如 CURL、axios、fetch、superagent 等)来生成请求。例如,在终端中使用 curl 发送请求:
以下代码可以在任意一个现代浏览器(为了避免 CORS,请访问 launchpad.graphql.com)中运行。
虽然构建 GraphQL 请求很容易,但是还需要实现很多其他东西,比如缓存,因为缓存可以极大地改善用户体验。构建客户端缓存不是那么容易,所幸的是,Apollo 和 Relay Modern 等提供了开箱即用的客户端缓存。
什么时候不该使用 GraphQL?
当然,完美的解决方案是不存在的(尽管 GraphQL 接近完美),还有一些问题需要注意,例如:
它有单点故障吗?
它可以扩展吗?
谁在使用 GraphQL?
最后,以下列出了有关 GraphQL 可能不是一个好选择的主要原因:
当客户端的需求很简单时:如果你的 API 很简单,例如 /users/resumes/123,那么 GraphQL 就显得有点重了;
为了加快加载速度使用了异步资源加载;
在开发新产品时使用新的 API,而不是基于已有的 API;
不打算向公众公开 API;
不需要更改 UI 和其他客户端;
产品开发不活跃;
使用了其他一些 JSON schema 或序列化格式。
版权声明: 本文为 InfoQ 作者【devpoint】的原创文章。
原文链接:【http://xie.infoq.cn/article/d64c500314123402e88c522f4】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论