大约一周前,Phil Sturgeon 的这则推文激起了许多 GraphQL 爱好者的关注。
相关上下文:https : //apisyouwonthate.com/blog/lets-stop-building-apis-around-a-network-hack
大约在同一时间,创建了这个名为 Vulcain 的项目。(这看起来还不错!)公告的一部分包括“ 您不再需要#GraphQL!”。 最后,马克·诺丁汉(Mark Nottingham)本周发表了一篇精彩的文章 HTTP/2的功能及其对API设计的意义。
这些文章以及项目让我开始思考这么一个问题:当世界上的一切开始运行 HTTP/2( 或者 HTTP/3)时,我们还有什么理由使用 GraphQL?
首先让我们了解 HTTP/2 哪些内容将改变 GraphQL 。HTTP/2 中有很多新特性,例如新的二进制格式和更好的 HTTP Header 压缩,但是在 GraphQL 上下文中让我们谈论的最有意义的事情是 HTTP/2 处理请求/回应。
打开 TCP 连接是许多HTTP/1客户端都希望避免的昂贵操作。出于这个原因,开发人员经常因其大量开销而试图限制请求的数量,例如批处理,查询语言,内联CSS/JS,sprite 等。HTTP/1.1试图通过持久连接解决其中的一些问题和 HTTP 流水线 技术。这两件事允许浏览器通过同一连接发送多个请求和响应。问题是这很容易受到 HTTP Header 阻塞的影响,这意味着一个缓慢的请求可能会使它后面的其他所有请求变慢。而设计 HTTP/2 的聪明人以不同的方式解决了这个问题:与这个新的二进制协议一起出现了新的交付策略。HTTP/2打开单个连接,但是使用新的二进制框架层多路复用请求和响应,其中每个帧都是 流。 然后,客户端和服务器便能够重建每个帧上存在的请求和响应流编号。这使得 HTTP/2 可以通过单个连接非常有效地处理许多请求。
不仅如此,HTTP/2 还具有一个称为服务器推送的新概念。无需过多赘述,服务器推送允许服务器在客户端请求响应之前抢先发送响应。最好的例子是样式表和JavaScript资源。在响应HTTP请求时,服务器可以检测到正在渲染的HTML页面,其中包含样式表,并且可以预测以下对 CSS 样式的请求,并且已经在客户端请求之前发送了响应。这就是Vulcain,我们在本文开头所讨论的项目就是用来有效地获取链接的资源。
是不是很酷?但这与 GraphQL 到底有什么关系?
GraphQL:单个请求即可全部搞定
GraphQL 的部分吸引力在于,它可以帮助我们更好地处理那些昂贵的 HTTP/1 连接。这是因为 GraphQL 可以让客户端在一次请求回应中即可从获取来自多个服务的响应数据。将此与以超媒体为中心的 API 进行比较,后者通常需要大量的网络请求(某些缓存可以提供帮助)。
https://graphql.org/ 将此特性用作“亮点”。
大多数宣称 GraphQL 对 HTTP/2 无效的人都在谈论这一点。如果发出请求的成本变小,那么从这种意义上讲,批处理API,诸如 GraphQL 之类的查询语言,嵌入式关系以及更大的自定义端点将变得不那么有吸引力了,这是完全正确的!但这是我们使用 GraphQL 的唯一原因吗?我不这么认为。
陷阱:HTTP/2客户端和某些应用程序服务器仍处于早期阶段
这不是一个很好的借口,但值得一提。在某些生态系统中,在应用程序层使用HTTP/2远未解决问题。你可以试试在 Google 上搜 Rack/Rails over HTTP/2 就可知一二。因为许多应用程序服务器都是使用请求/响应模式构建的,并且实现 HTTP/2 流模式并非容易的事,尤其是对于某些框架而言。但是,这不是一个很好的借口,许多生态系统确实为它提供了良好的支持,并且从理论上讲,我们仍然应该致力于使其变得更好!(尽管大多数代理服务器都支持它,但是如果应用服务器陷入这种请求/响应模式,则很难执行服务器推送之类的操作。)
GraphQL不仅涉及减少往返请求或关于过度/不足的获取
尽管我们看到这两个特性被大量的宣传,但 GraphQL 不仅为我们提供了减少往返请求或减少通过网络传输的字节数的功能。
GraphQL 的功能以及最大的折衷之处就是它以客户为中心。在过去的几年中,这在很多人的心中是一个令人担忧的问题。丹尼尔·雅各布森(Daniel Jacobson)在5到7年前就其中一些问题写了许多惊人的文章。这是另一篇文章。
我们的 REST API 虽然非常有能力以通用方式处理来自我们设备的请求,但并未针对其中的任何一个进行过优化。
请注意,这并不一定与 REST 需要我们发出更多请求或传输不必要的数据有关。更多有关设计 API 的信息,该 API 支持多种不同的客户端用例。解决此问题的一种常见方法是让客户端逻辑更接近服务器,例如2012年该帖子中提到的Netflix的客户端适配器。从那时起,他们的一些团队甚至一直在使用GraphQL。该BFF模式是另一个抽象,旨在解决类似的问题。
GraphQL 通过帮助我们构建能够将客户端用例编译为服务器资源的服务器引擎,重新定义了客户端服务器边界。持久查询使这更容易理解,本质上是客户端生成的服务器资源。
作为服务器端抽象的 GraphQL 在讨论它在HTTP/2世界中是否仍然有意义时要牢记。尽管维护各种用例可能会导致典型的基于终结点的 API 出现问题,但GraphQL 使 API 提供程序可以专注于公开更多的可能性,而无需考虑现有客户端的成本,也不必增加维护大量不同资源的复杂性。(它的确增加了成本:难以优化性能;并非总是可缓存的。这个经常需要在高度可定制的API中进行同样的权衡取舍)
客户端开发人员经验
在这些文章中,我倾向于将重点放在服务器端的内容上,但是要提醒自己的是 —— GraphQL 在客户端级别上尤其受欢迎!将 GraphQL 片段与我们在现代前端框架中看到的组件模式配对时,绝对是很棒的做法。同样,与持久查询配合使用,GraphQL客户端开发人员的体验可能会非常令人难以置信的棒。
整个包装使它变得很棒
GraphQL 并没有什么特别之处,而且是可以替代的技术。Typed Scheme?只需使用OpenAPI!服务器端抽象来处理多个客户端用例?有很多方法可以做到这一点。内省?超媒体可以允许客户端发现操作,也可以从根开始。惊人的GraphiQL?我确定OpenAPI会有帮助。始终可以重新创建GraphQL的部分内容。但是,在一个规范下找到的这一切,使GraphQL具有吸引力,并且对我们许多人来说都很棒。我怀疑这也是促使它增长如此之快的原因。关于构建 API 风格有很多指导,而且针对 GraphQL 语言特定的库往往质量很高且被广泛采用。
网络仍然是(永远是?)的约束
这是最后一个问题。无论网络请求有多快,它们似乎总是会受到某种约束。这就是为什么我们不像典型的编程语言对象那样设计Web API的原因:
企业应用程序体系结构模式的摘录:https : //martinfowler.com/books/eaa.html
虽然 HTTP/2 绝对支持更细粒度的请求,但我认为这种权衡仍然存在。
HTTP/2 可以帮助 GraphQL 吗?
尽管 GraphQL 给我们带来了许多其他重要的东西,但是 HTTP/2 仍然很棒。将来可能要考虑的事情是,我们是否也可以将这种功能带给GraphQL。像这样:
query {
viewer {
name
posts(first: 100) @stream {
title
}
}
}
我们仍然可以在使用HTTP/2流的同时使用GraphQL的服务器端抽象,它是声明性查询语言。Facebook 已经在使用 WebSocket 上进行了探索。我们需要更多的探索,我需要看看这个多,但我知道很多人已经在用一些指令,如@defer
,@stream
和@live
。
最后的话
HTTP/2 非常棒,尤其是本文中的示例令人震惊!如果 GraphQL 只是减少请求响应的往返次数或节省字节数的一种方法,那么您可能会对 HTTP/2 更满意,但是,如果您还感受到了本文中讨论的其他功能,那么你会意识到 GraphQL 给我们带来的不仅仅这些。
YHFHing 发布了165 篇原创文章 · 获赞 45 · 访问量 4万+ 私信 关注