GraphQL在服务器端实现上是否成为最佳实践?
这篇文章是 GraphQL Advent Calendar 2020 第14天的文章。
上一篇文章是由 @joe-re 先生撰写的「探索库的实现及游标分页中游标格式的最佳实践」。
引子
我个人认为,GraphQL是在2010年代末出现的技术中特别强大的应用实现模式之一。尽管它的实现相对简单,但由于使用场景的多样性和使用者角度的不同,很难完全理解其整体架构,因此我感觉到它的潜力还未得到广泛认知和应用。
这次主要从服务器端的视角出发,分解和解释构建GraphQL的要素,同时也想写一下在利用GraphQL时对Web应用开发和相关工程师可能会发生的变化。简言之,以前前端开发人员、Web应用程序人员、无服务器人员和微服务人员各自分离,但GraphQL将把所有知识连接在一起!这就是我想说的。
由于我之前写过有关GraphQL整体概述、使用背景以及前后端都面临的挑战和好处的文章,希望你也可以参考一下那篇文章。参考链接:GraphQL的整体概述与Web应用开发的未来。
GraphQL的设计模式
GraphQL的组成要素可以分解为以下几个部分。
-
- フロントエンド分離
-
- API Gateway パターン
-
- Serverless, Microservices
- API Gateway パターン, Serveless/Microservicesパターンの応用としてのgRPC
我希望通过观察这些问题和解决方案来更好地理解GraphQL。
在那之前,GraphQL作为一种查询语言
因為這是常被討論的部分,所以我會簡短地說明。
-
- リクエスト, レスポンスに型がある
-
- self-documenting
-
- クライアントが要求した通りにデータが変えるのでオーバーフェッチを防ぐことができる
- リクエストを束ねる事でサーバーとの通信回数を減らす事ができる
这次我们将从其他的角度来看。
前端分离
使用GraphQL的前提是前端和服务器端分离,并且使用以HTTP表示的API。所以我故意提到了这一点。
展示领域分离
当把展示逻辑和领域逻辑分开时,更易理解。
可以将同一基本程序适用于多个展示,而无需重复代码。
由于用户界面不易测试,将其分离以便专注于可测试的逻辑部分。
可以轻松添加用于脚本API或外部服务的API,以供可选的展示部分使用。
展示部分的代码需要与领域部分的代码具备不同的技能和知识。
将服务器端与前端分离的原因与PresentationDomainSeparation的问题相同。由于服务器端和前端的技能和知识完全不同,实现的生命周期也不同,所以如果服务器端负责处理展示层(主要是HTML的生成),首先应该分离的是将HTML的生成从服务器端分离出来。
前端最佳实践已集中在前端框架中。
自2017年以来,next.js和Nuxt.js作为单独的前端框架逐渐崭露头角,并在其中汇集了前端最佳实践。对于实现丰富的设计和页面数量较多的应用程序,这些框架已经成为主流。使用这些框架可以利用现代化的前端实现最佳实践进行开发。
我认为如果你想了解最近前端的动向,可以查看@mizchi先生最近的资料。
前端学习#1:基调演讲 – 重新定义前端领域。
可以通过使用GraphQL来
不仅限于GraphQL,通过服务器端提供API并将前端分离,可以更高效地进行现代化的前端开发,实践最佳方法。
API网关模式
来源:https://www.apollographql.com/docs/apollo-server/
转载来源:https://www.apollographql.com/docs/apollo-server/
在设计模式中,像Servelss和Microservices这样的设计模式经常被使用。当API的数量增多或客户端增多时,可以通过使用API Gateway模式来解决这个问题。API Gateway模式包括Gateway Routing Pattern、Gateway Aggregation Pattern和Gateway Offload Pattern作为其子集。
在URL为基础的API Gateway的开源实现中,有Kong Gateway和KrakenD。在Kubernetes领域中,似乎会使用Istio Ingress。在云端环境中,Azure拥有Azure Application Gateway和Azure API Management,而AWS则拥有Amazon API Gateway。
API Gateway继承了L7负载均衡器的特点进行实现(例如,Kong Gateway作为nginx的功能扩展进行实现)。为了更好地理解API Gateway的功能,让我们来看一下KrakenD的功能列表。
-
- モニタリング
ロギング
スタッツ
セキュリティ
SSL
セキュリティポリシー
スロットリング
Rate Limit
ユーザークォータ(使用量)
Proxy
OAuth
プロトコルトランスレーション
ロードバランシング
QoS(Quoerity of Service)
並行呼び出し
サーキットブレイカー
Grained Timeout
Cache
キャッシュヘッダー(HTTP)
Aggregation
Merge sources
Manipulation
Transform
Filtering
Whitelist
Blacklist
Decoding
From JSON, XML…
通过将原本在API服务器中处理的操作,特别是中间件层的操作,集中到网关中,就可以将其交给API网关进行处理。
使用API Gateway的影响对服务器端的实现。
通过API网关来代替中间件层的角色,可以使得后端应用服务器实现更轻量级的中间件层。在采用Serverless或者微服务模式中存在多个后端应用程序的情况下,采用此方法可以避免每个负责域逻辑的应用程序都需要实现类似的中间件。
作为API网关的GraphQL
在先前的API网关实现中,中间件应该专注于处理,并尽量不涉及领域逻辑,类似于简单的L7负载均衡器的实现和使用。但是在GraphQL中,将作为应用程序实现API网关的功能。您可以使用任何编程语言进行编写(如果没有特殊原因,建议使用JavaScript / TypeScript)。虽然这些库并不从一开始就具备作为API网关的所有功能,但您可以实现它们并添加进去。随着GraphQL生态系统的发展,这些库也在不断扩充,您可以利用它们进行实现。
通过使用GraphQL
使用GraphQL可以继承API Gateway的特点,从而享受使用API Gateway时的好处。
无服务器,微服务
GraphQL和Serverless、Microservices之间没有直接的技术关系,但在使用Serverless、Microservices时,采用API Gateway是常见的做法。GraphQL可以作为API Gateway运行,因此会涉及到GraphQL的特点和Serverless、Microservices的特点,所以在这里介绍一下。
无服务器即是
-
- サーバーレス アプリ: アーキテクチャ、パターン、および Azure の実装
-
- サーバレスパターン – AWS
-
- サーバーレスのおさらい – AWS
- Serverless Architectures – martinfowler.com
在中国有许多不同的定义关于无服务器架构模式,但我个人的解释是,它是通过使用云平台(如Azure、AWS或GCP)提供的PaaS、FaaS、数据库和数据存储来构建应用程序的模式。
「微服务」是什么意思?
-
- Azure のマイクロサービス | Microsoft
-
- マイクロサービスの概要 | AWS
- マイクロサービス (microservices) とは – 概要 | Red Hat
根据AWS的定义引用来看
微服务是一种针对软件开发的体系结构和组织方法,通过由多个小型独立的服务组成软件。每个服务通过明确定义的API进行交互。这些服务由小型自主团队负责。
微服务架构可以方便地实现应用程序的扩展,并缩短开发周期,从而加速创新实现和新功能的市场推出。
无服务器和微服务的好处。
这些架构模式的共同点是
-
- 担当するドメインロジック毎にプログラミング言語を選択できる
-
- 担当するドメインロジック毎にデータストアを選択できる
-
- 部分的にスケールアウト、スケールアップできる
-
- 責務分離がなされた設計になる
-
- ドメインごとに開発チームを分離できる
- 大規模、エンタープライズの開発に耐えうる
还有其他选项。(如果想要了解更多信息,请参考Microservices和Serverless的资料。)
应用程序编程接口(API)的演示领域分离
GraphQL负责作为与使用GraphQL的客户端进行交互的API的模式。这是API的演示领域分离,后端应用程序可以专注于领域逻辑,从而减少开发工作量,并实现对变更的高度适应性的API。由于领域逻辑与表示层分离,因此可以在不影响客户端的情况下进行领域逻辑的替换和后端应用程序架构的更改。
HTTP离线加载
如果要引入API Gateway,API Gateway将负责与客户端的交互。前端和本地应用程序与服务器的交互通常采用HTTPS作为基本协议,因为HTTPS作为协议对于各种用途都具有抗击能力,但存在大量开销,而且在建立通信的握手过程中需要相当长的时间。因此,在采用Microservices模式时,可能会选择使用gRPC代替HTTPS。这被称为网关卸载模式。gRPC将在下文中介绍。
※ 有时会将HTTPS转化为HTTP进行进一步处理,但如果是在完全隔离的私有网络之内的闭环环境中使用,尚可接受。然而,如今随意地在云端部署应用程序,采用HTTP进行服务器之间的通信是危险的,因为不知道数据经过哪个网络。
通过使用GraphQL
无服务器计算使得微服务的发展更加容易。在开发的早期阶段,可以根据领域的不同自由选择语言和数据库,这将使得避免强制设计的优点更加明显。
蛇足: Lambda容器映像的支持对开发产生的影响
最近Lambda开始支持容器镜像。现在可以在Lambda上运行Docker的容器镜像。由此可能引发的设想是,
-
- 例えばStripe決済のAPIを実装したLambdaコンテナ
-
- 例えばCloudinaryのような画像と寸法を渡したら最適な画像を生成してくれるLambdaコンテナ
- 例えばOAuth2.0を実装したLambdaコンテナ
也许会出现将类似这样的东西作为开源软件发布的时代。这样一来,我就可以幻想着领域逻辑所需的代码将进一步减少。
gRPC
尽管和GraphQL无关,但我想提及一下在应用API网关模式、无服务器/微服务模式时常用的gRPC。
我想要探讨一下GraphQL在各种数据源中连接的情况,特别关注gRPC的使用。
gRPC(gRPC远程过程调用)是由Google开发的开源远程过程调用(RPC)系统。gRPC使用HTTP/2作为传输协议,并使用Protocol Buffers作为接口描述语言。gRPC提供了认证、双向流、流量控制、阻塞和非阻塞绑定、取消和超时等功能。它可以在多种语言中使用跨平台的客户端和服务器绑定。
gRPC利用HTTP/2作为传输层,但在gRPC客户端和gRPC服务器之间的应用层gRPC协议通信中,能够以极低的开销和高性能进行通信。在gRPC的应用层中,不需要考虑HTTPS,但在基础设施层面上,可以将其构建为一个HTTPS应用。通过使用gRPC,您可以同时实现HTTPS安全通信的特性和低开销的服务器间通信。
gRPC是一种远程过程调用(RPC)的通信协议,它可以调用在不同实例上运行的应用程序中的函数。在gRPC服务器应用程序中,我们只需要考虑函数的参数、返回值(值和异常)以及领域逻辑。它可以用于大多数主流语言编写。
请转至gRPC文档以获取更详细的信息。
迄今为止的HTTP应用
我想你在谈论HTTP应用程序框架时可能见过以下的图表。
在HTTP应用程序中
-
- HTTPリクエストとレスポンスのハンドリング
-
- HTTP HeaderやCookieを利用した、認証やCacheやSessionなどのリクエストMiddlewareの実行
-
- URLとロジックのルーティング
-
- ドメインロジックの実行
-
- レスポンス middlewareの実行
- HTTPレスポンスの構築
有多个关注点,为了将它们分离出来,像干净架构那样的分离级别被提出。HTTP处理层和其他中间件都很复杂,所以有必要准备这样的图表。
当采用GraphQL和gRPC时,责任划分的情况。
GraphQL作为API网关进行HTTPS通信,并通过集成中间件在干净架构中负责外部接口、网关层、控制器和呈现层。采用gRPC的服务器负责领域逻辑,可以将其表达为核心逻辑,仅专注于服务、用例和实体等简单函数。不需要承载任何不必要的上下文,因此无需像HTTP框架那样使用重量级库,只需使用几乎只有编程语言的简单代码即可进行编码。
gRPC服务器应用的开发方式与FaaS相似。
在可用于云平台的FaaS(函数即服务)中,如Azure Functions、AWS Lambda和GCP Cloud Functions中,平台已经为其提供了各种触发器、输入和输出,编码本身只需编写简单的函数。由于这些FaaS与gRPC的编写方式相似,因此可以采用类似的开发经验进行实现。
通过使用GraphQL + gRPC的方式
负责处理域逻辑的应用服务器可以更专注地编写域逻辑。由于性能更高,它能使开发接近项目完成时的最终形态。
GraphQL 構建设计模式总结
GraphQL具有API网关模式的方面。因此,它很容易发展为无服务器或微服务模式,并且很容易使用用于服务器间通信的gRPC。通过使用GraphQL和gRPC,我们可以将域逻辑从负责的服务器中分离出HTTP协议,并且我们发现可以使用小型函数编写逻辑。
如果已经有一个具有RESTful API的HTTP应用程序,那么首先可以通过HTTPS连接到GraphQL。如果您愿意支付变更实施成本,或者需要改善响应速度,逐步从RESTful的HTTP切换到gRPC可能是一个不错的选择。
基于这些情况,对未来的网页开发进行思考和考虑
我考虑到,也许未来的世界线会有这样的可能性,我希望能够分享我的思考和研究成果。
GraphQL是否成为服务器端实现的最佳实践?
微软、谷歌、亚马逊、脸书、推特、艾滋制作、优步、奈飞等世界巨头正逐步转向GraphQL、微服务和无服务器等技术,并通过其生态系统来集结最佳实践。
利用GraphQL是踏上现代Web生态系统构建最佳实践的捷径。以前,采用微服务模式或gRPC的使用仅适用于超大规模解决方案,但GraphQL可能已经将其距离大大缩短,可以供小团队使用。我感到这可能是GraphQL隐藏的功绩之一。
或许在系统架构的选择中,站在巨人的肩膀上是非常重要的。
可能会减少编写HTTP应用程序的机会..可能吗?
我在gRPC的部分谈到了这个问题,如果GraphQL负责HTTP,并且应用程序使用gRPC来处理后续的领域逻辑,那么应用程序工程师可能会逐渐将实现领域的范围变成FaaS或者gRPC应用程序。因为它们比HTTP应用程序更接近简单的函数,所以开发工作量要少得多,从而提高了生产力和开发体验。通过GraphQL在整个服务中使用HTTP,后端的应用程序将不再需要HTTP。
那么,像Rails这样的单体式HTTP应用程序是否会变得不再需要呢?不会。单体式架构模式是为了从0到1创造出来的,适用于小团队的设计模式。当团队成员较少、项目可能持续数年且存在高变动性的情况下,我认为采用单体式架构是更好的选择。如果一开始就知道项目将持续数年,且可以在一开始就招齐开发人员,那么可以跳过采用单体式架构,直接选择适用于大规模开发的设计模式。
我认为,在现代开发方法中,有逐步变更的解决方案,所以只需要在适当的时机将其发展为GraphQL或微服务的模式即可。
借鉴了Cookpad公司在从Rails迁移至gRPC的案例。
参考资料:Cookpad 采用 gRPC 之前所面临的服务间通信问题以及在 Ruby 上运用 gRPC 的改进措施。
此外,我想分享一下作为个人所持有的阶段性架构变更策略。
假设使用Rails/Laravel作为API(如果不是的话,首先将前端进行分离),我们将逐步分离Rails所拥有的功能,使用类似于Auth0的IDaaS来处理OAuth,将异步任务转化为Serverless形式,在API接口的每个阶段引入GraphQL,最终将API逐步替换为gRPC + 强类型语言。最终,我们将淘汰Rails。
关于这个问题,我听说那些没有经验的工程师加入使用Serverless的公司时,由于他们在FaaS上的实现较多,所以对服务器和应用程序的概念了解较少。将来,可能会出现一个由分离架构组成的系统,从工程师的技能要求来看,HTTP可能会成为一个不再需要的世界线…
GraphQL能否成为前端和后端之间的桥梁?
大多数前端开发者对后端存在不满的主要原因是因为没有实现PresentationDomainSeparation,导致后端掌握了整个演示层逻辑,或者API接口定义难以理解、没有文档、分散不集中。
我希望API Gateway能够越来越多地采用类似GraphQL这样的架构,因为GraphQL是为了解决前端与服务器端之间的分离而存在的。
GraphQL的采用时机。
GraphQL是一种能够从开发初期就可以引入,并且在开发结束前始终持续使用的长寿应用程序。由于可以逐步引入,因此可以在任何时间点开始使用。
GraphQL的实现本身非常简单
无论我说了多少次,这是一个非常简单的结构。只需要花1至2小时学习Apollo Server的教程,就能掌握实现的感觉。
使用过GraphQL的人通常会以相似的方式分享GraphQL的优点,但我印象中未曾接触过GraphQL的人在仅仅通过信息来谈论GraphQL时会感到有些困惑。我认为使用GraphQL是最快的了解途径,所以请先尝试一下。
要开始使用GraphQL,需要对前端和服务器端都有了解。
由于GraphQL可以减轻前端和后端的负担,所以前端和后端必须作为利益相关者存在。因此,如果只有GraphQL前端需要,或者只有后端需要,就无法引入GraphQL。除非双方都理解未来的好处,否则无法采用此应用程序。
整理
我最近研究了将GraphQL进行元素分解以及使用GraphQL进行近2到3年的考察。尽管GraphQL包含了许多Web的最佳实践元素,但个人认为它在前端中的应用并不普及的原因可能是因为大部分对GraphQL的认识都是从前端的角度,而对于后端来说了解得较少。我希望未来能够更多地使用GraphQL,并定期从后端的角度发表关于GraphQL的观点。希望前端和后端能够更好地协作。
所属公司:EBILAB有限公司
在所属的EBILAB株式会社,我们正在开发面向服务业和餐饮业的数据整合、BI和机器学习的服务TOUCHPOINTBI。EBILAB利用Azure Serverless在数据基础设施和数据分析方面,使用GraphQL、Nuxt.js和Laravel构建Web应用程序。我们相信,能够以4、5人的开发团队规模进行这样的开发,是因为采用了Azure的Serveless、GraphQL和Nuxt.js等现代化架构,可以沿用Web的最佳实践。同时,采用GraphQL可以相对容易地进行客户端的横向扩展,这是一个好处。
如果方便的话,请关注我的Twitter账号@saboyutaka。
最后
GraphQL太棒了
祝你新年快乐。