GraphQL的整体概述和Web应用程序开发的未来
太长不读
-
- GraphQLはクライアント側とサーバー側の双方の複雑化を解決するために利用されてる
-
- フロントエンドにとってGraphQLはHTTP上で動く信頼できる唯一のリソースとして振る舞う
-
- フロントエンドの状態管理のベストプラクティスとしてのApollo Client
-
- クライアントファーストなAPI, GraphQLはWeb APIのベストプラクティスになり得る
- クラシックアプリケーションを改修することなくGraphQLとモダンフロントエンドで今どきのアプリを作れる
首先
尽管GraphQL是一个非常好的软件规范,但由于具有多个方面,很难立即理解,并且在日本尚未得到广泛接受的印象依然存在。如果简洁地说,GraphQL被称为“适用于所有前端的API BFF”,但很少有人能仅凭此理解它。本文将介绍GraphQL的应用背景、解决的问题以及未来Web的变化。由于这是一个抽象的概念性讨论,不涉及详细的实现。关于实现,建议阅读GraphQL最大的生态系统之一Apollo的文档,那里整理得非常好。
如果您从未使用过GraphQL,您可以尝试使用https://github.com/APIs-guru/graphql-apis中的2到3个API,以便大致了解它们的特性。(我个人喜欢宝可梦、星球大战和Spotify。) 使用GraphQL API,您将能够使用它们而无需关注API的实现方式。
我想试试看进去。
GraphQL的背景是其被广泛采用和使用。
首先,我想从最近Web开发趋势和GraphQL的出现背景开始。
前端开发
该文章中对前端的定义是指在用户手中运行的终端应用程序。包括面向PC浏览器的应用程序、iOS、Android和可穿戴设备上的应用程序。PC浏览器的应用程序单独被描述为Web前端。
前端的多平台化
近年,除了开发传统的面向PC浏览器的Web应用程序之外,使用Web技术开发适用于iOS和Android智能手机设备的原生应用程序,以及适用于Apple Watch和Fitbit等可穿戴设备、以Electron为中心的桌面应用程序等多种客户端处理数据资源的跨平台应用程序已经成为常见做法。每个设备的客户端应用程序利用由服务器端提供的Web API,并具有渲染逻辑。每个设备的客户端应用程序在相同的服务(如Facebook、Instagram、Twitter等)中具有不同的用户界面(UI),并在API中请求稍微不同的数据。在过去,为了响应这些请求,我们会针对每个平台准备一个中间层的API(作为API聚合,即BFF),或提供包含大量数据以覆盖所有用例的API(导致超取数据)。这是因为随着客户端变得复杂和多样化,服务器端需要处理这些要求,导致服务器端API实现的负担增加,而在开发资源有限的情况下,很难完全应对所有情况。
富前端化发展,同时在Web前端中出现了像React.js、Anglur.js、Vue.js等组件库以及利用它们的渐进式框架(Next.js,Nuxt.js)等,客户端渲染(CSR)也成为常见现象,由此导致API也开始需要更复杂的功能。
前端应用程序的特性是由于产品的生命周期和发布周期较短,对API的需求经常发生变化。另外,用户设备和网络环境的差异也会影响应用程序的运行环境,从而使需求变得更加严格。因此,为了使前端应用程序变得更好,对API的要求也变得更加严格,这增加了服务器端的实现负担。
服务器端
微服务化
从2010年代中期开始,随着Docker的普及,采用Microservices和Serverless等多个应用程序和多个数据库组合实现的服务器端架构模式变得普遍。由于每个端点通常是由不同的语言和不同的框架实现的,并且具有不同的规范,为了尽可能减少与端点用户的沟通成本,制定符合Open API等规范的API文档成为推荐做法。随着不同规范的API增多,前端的实现负担也会增加。
服务器端为主体的API设计
另外,与前端应用程序和数据库相比,服务器端应用程序和数据库具有更长的寿命,一旦创建就难以更改。由于实现靠近数据源,因此倾向于实现与数据源适合的方式。因此,与前端应用程序请求的API规范相反,实现会有所不同。特别是REST API似乎会促使实现数据库中的原始表结构的API。
由于这些原因,API的设计是根据服务器端的需求制定的。
为了满足需求和供给的双方要求,引入GraphQL作为中间层。
由于需求和供给的复杂化,双方都会变得难以利用。结果是,过于复杂的应用程序由于通信成本的增加而导致开发效率下降。API的复杂性直接影响着开发和运营人员之间的沟通复杂度。如下图所示,每条线都会导致人与人之间的沟通。随着客户端和服务数量的增加,沟通会呈二次函数式增加。
来源:Tech Crunch- Apollo为其GraphQL平台筹集了2200万美元。
GraphQL是基于这样的背景而出现的。GraphQL扮演着前端和服务器之间的代理角色。前端不再向API服务器发送请求,而是向GraphQL应用程序发送请求。收到请求的GraphQL应用程序会解析查询,并向配置的数据源发送请求。
前端可以访问整个服务的所有数据,所有前端都连接到一个单一的GraphQL应用程序。同时,所有服务器端应用程序也连接到GraphQL。
来源:https://www.apollographql.com/docs/apollo-server/
Source: https://www.apollographql.com/docs/apollo-server/
在传统的API设计中,“前端的数量 x API端点的数量”是唯一的使用模式,而通过GraphQL实现的API设计中,所有前端仅使用单一的API端点,服务器端成为一个GraphQL应用程序的单个客户端。因此,前端的数量+端点的数量会发生变化。通过将乘法变为加法,可以将组合的二次函数增长变为线性增长,实现可能性。
前端与服务器端的关注点分离
GraphQL可以完全分离前端和服务器端的责任。
假设有一个应用程序,它被实现为以Nuxt.js作为Web前端应用程序,以Ruby on Rails作为服务器端API。现在我们决定在它们之间实现GraphQL作为中间层。
从架构层面来看,应用程序可能会显得更加复杂,但如果将其分为前端和服务器端进行考虑,视角就会有所变化。
在开发中,会分成前端、GraphQL和服务器端API三个团队。从前端的角度来看,GraphQL看起来像是一个单一的数据源;而从服务器端来看,GraphQL则像是一个单一的客户端。
GraphQL被前端和后端分别从完全不同的角度来看待。因此,我希望能从每个角度来解释一下关于GraphQL的内容。
在前端的角度看GraphQL。
GraphQL的规范在前端中经常被提及,带来了许多好处。
以下是通常提到的GraphQL的优点。如果在前端谈论GraphQL时,通常会涉及以下内容,请查阅相关资料:
1. グラフ型のデータモデル:RESTful APIよりも柔軟で効率的なデータ取得が可能。
2. クライアント指向のフェッチ:クライアントが必要なデータを指定し、一度のリクエストでまとめて取得できる。
3. 高性能と低帯域幅:必要なデータのみを取得するため、ネットワークトラフィックを削減し、応答時間を短縮できる。
4. ドキュメントと型システム:APIの正確なドキュメント化とタイプエラーの検出が容易。
5. バックエンドの切り替えの容易さ:既存のRESTful APIとの共存や徐々な移行がスムーズに行える。
注意:这是对原文的表意进行的翻译,可能会有一些细微差异。
-
- リクエストもレスポンスも型安全である事
-
- Self-documenting(自己文書化)である事
-
- Generatorがあるためフロントエンドでレスポンスを型安全で利用出来る事
-
- TypeScriptと相性が良い事
- 要求した通りのレスポンスが返るためオーバーフェッチにならない事
对于前端而言,GraphQL是在HTTP上运行的信赖可靠的唯一资源。
来源:Apollo文档 – GraphQL Playground
GraphQL和SQL是两种不同的查询语言。SQL是一种在数据库管理系统中使用的语言,用于操作数据库。而GraphQL是一种查询语言,GraphQL客户端可以向GraphQL应用程序发送查询,并返回与所请求的查询匹配的对象结构(以JSON格式)。因此,只要GraphQL客户端了解如何查询数据和返回数据的方式,就可以进行开发,无需了解服务器端的具体规格。
传统的REST API通过执行返回以RESTFul表示的数据集合的函数(RPC)来获取由服务器应用程序拥有的数据,前端通过执行这些API(函数)并组合它们来模拟服务器端应用程序拥有的数据。因此,前端需要从文档中理解各个函数的工作方式以及它们如何与其他函数连接。
我认为REST API和GraphQL API可以通过”操作抽象化数据的多个函数”和”唯一的资源和查询”的对比来进行更容易的理解。
通过使用GraphQL,前端无需了解由服务器端提供的API框架的规范、API的设计理念(如SOAP或RESTFul)。
GraphQL在Scheme中提供了预先定义的关系和数据类型,并可以通过GraphQL Playground这个执行环境进行使用,它可以作为可执行的文档来起作用,这样就不再需要针对每个端点阅读API文档了。
通过GraphQL API,应用程序可以像访问单一数据库一样访问其拥有的所有数据,通过模式完全表达数据之间的关系,并可以访问整个数据集。前端可以利用这些数据,根据用例提取数据,并通过发送更改请求与GraphQL应用程序进行交互,以构建用户界面并将其传递给用户。
尽管在这里并没有涉及到图论的话题,但从前端的角度来看,GraphQL 并不需要太多地了解图结构的必要性。只要能编写查询,并返回所需的 JSON 格式的 API,就足够了,不会有问题。
作为前端状态管理的最佳实践,Apollo Client
以下是原文的中文翻译:
尽管与GraphQL规范本身无关,但开始独立演进以符合GraphQL规范的Apollo Client正成为GraphQL的一个优点,因此我们将对其进行介绍。
Apollo Client 是一个用 JavaScript 编写的 GraphQL 客户端,在 JavaScript 中被视为事实标准。它是为 React.js 编写的,但也有适用于其他库 (如 Angluar.js 和 Vue.js) 的版本。同时也有适用于 iOS 和 Android 的版本。
什么是Apollo Client?
Apollo Client是一种为JavaScript应用程序提供完整状态管理的库。通过仅编写GraphQL查询,Apollo Client可以处理数据的请求和缓存,就像处理UI更新一样。
当使用Apollo客户端获取数据时,您可以以符合最新的React最佳实践的可预测声明性方式来构建代码结构。使用Apollo,您可以更快地构建高质量的功能,而无需编写繁琐的数据管道模板。
来源:https://www.apollographql.com/docs/react/
Source: https://www.apollographql.com/docs/react/
Apollo Client在作为一个执行GraphQL查询的客户端的同时,还会将接收到的数据(通常存储在内存中)进行缓存。而且,这个缓存被用于非常好地管理状态。Apollo Client会在发起查询时先查询本地缓存,如果数据不存在,则会向远程GraphQL服务器发起网络请求。因此,使用Apollo Client的JavaScript代码无需担心请求的数据是存在于本地还是需要从网络中获取,可以直接访问数据。无论是访问本地缓存还是通过网络访问数据,都使用相同的查询方式。可以灵活地设置是否使用缓存,以及在其他查询中重复使用数据等。
过去使用状态管理库如Flux、Redux或Vuex是常见的,但是通过使用Apollo Client,前端状态管理的实施变得更加轻松。
在 Apollo Client 的案例研究中,发布了一个成功的案例,证明在 Major League Soccer 的应用程序中成功删除了接近5000行的 Redux 代码。
GraphQL是一种对于前端来说具有高度可重复利用性的技术。
假设将GraphQL应用于所有应用程序,它可以用以下的图来表示。
用GraphQL,所有的服务器端应用程序都被隐藏在前端视角下。通过使用GraphQL,客户端可以专注于前端实现,而无需关心服务器端的实现。由于GraphQL的使用方式始终相同,无论服务器端应用程序是什么,因此可以说GraphQL是一种具有高度可重用性的技术。
同样,iOS、Android等平台也能够通过GraphQL访问,因此可以利用相同的GraphQL API来实现不同平台上的客户端应用,从而便于进行多平台化和多客户端化。
GraphQL 解决了前端的问题。
-
- API利用のコミュニケーションの増大問題を解決した
-
- API毎に異なる仕様を学習するコストをなくすことが出来る(ドキュメントを読む量が減る)
- フロントエンドの状態管理をApollo Clientが解決した(しそう?)
从服务器端的角度看GraphQL
接下来,我想从服务器端的角度介绍GraphQL。在这里,图论和实现的概念终于出现了。
GraphQL的操作步骤。
GraphQL是一种可以用图论和树来解释的技术。关于GraphQL的概念,这里有一个很容易理解的资源。
GraphQL 概念可视化
请使用专业术语。
作為圖論術語
-
- ルート
-
- ノード
- 木
作为GraphQL的术语
-
- Scheme
-
- Data Type
-
- Query
-
- Resolver
- DataSource
出现了。
可视化的概念
出处:可视化的GraphQL概念
在Scheme中声明的数据结构可以像图一样连接在一起(因此称为”Graph”QL)。当发出获取数据的查询时,查询将被解析为树形结构。
GraphQL的工作原理
-
- 在Scheme中预先声明数据和对象之间的关系。声明的Scheme将成为一个图形结构。
-
- 客户端使用查询来获取数据。查询是从一个节点作为根的树结构中提取操作。
-
- 解析和构建的树的节点将从上到下逐步调用并解决描述解决函数(解析器)。
-
- 解析器调用DataSource类的函数。 DataSource类描述了发送HTTP请求,向数据库发出SQL查询或读取文件等行为。
- 当所有节点的解决工作结束后,返回响应。
整理一下的话,我认为并不那么困难。GraphQL简单来说,是在图形中表示的Schema,以及从图形中提取树状查询和解析节点的函数一起运行的HTTP应用程序。通过连接数据源,以及利用符合HTTP规范的控制(例如身份认证和缓存),可以提供复杂的API。
多种多样的数据源
来源:https://www.apollographql.com/platform
Apollo Platform将GraphQL表达为这样的形式。在GraphQL中,持有数据的服务器或应用被称为DataSource,它可以连接到各种各样的API。这些API包括通过HTTP提供的REST API、通过SOAP、gRPC提供的应用程序、数据库等等。因为解析器(Resolver)只是一个简单的函数,所以在程序中可用的数据实际上可以是任何数据,几乎没有限制。
数据源的示例
-
- Ruby on Railsで実装されたREST APIを利用するHTTPクライアント
-
- SOAPで実装されたAPIを利用するHTTPクライアント
-
- gRPC + Goで書かれたAPIを利用するgRPCクライアント
-
- MongoDB クライアント
-
- Redis クライアント
-
- Elastic Search クライアント
-
- S3クライアントとファイルリーダー
-
- Excelを読み込むリーダー
-
- ソースコードベタ書きのオブジェクト
- スクレイピングで取得したデータ
在每个API连接上,DataSource是一个单例的服务类。它定义了用于向API发送请求的函数,并被Resolver使用。将实际的API处理封装起来,从Resolver的角度看,可以以一种隐藏处理逻辑的方式实现,这样更容易进行责任划分。
GraphQL应用的实现
-
- Schemeの定義
-
- 定義されたノード(TypeやField)のResolver関数を実装
- DataSourceでAPIの呼び出しなどを実装
我們將繼續進行以下三件事情。
通过使用GraphQL,对于服务器端的好处。
与使用GraphQL API的客户端开发团队的沟通成本降低。
通过定义 Scheme,客户端可以解析 Scheme 和查询的规范,并且可以为 Scheme 添加相应的注释,因此 Scheme 实际上成为了 API 文档。由于服务器端被隐藏起来,客户端也无需了解 API 的具体实现方式。开发数据源 API 的团队只需要与负责实现 GraphQL 的团队进行沟通即可。
从服务器端的角度来看,只有一个客户端。
使用GraphQL后,从服务器端API的角度来看,客户端将通过GraphQL的解析器和数据源替代请求前端。
由于前端直接面对客户端,因此需要考虑前端方面的限制。
-
- 過酷なネットワーク環境、デバイス環境を考慮した最小限のデータ送信
-
- UI毎に異なるデータ形式
- etc..
通过GraphQL作为前端代理发送请求,使服务器端API的设计相对容易。
-
- フロントエンドのユースケースについて過度に意識せずにAPIの設計が出来る
-
- ネットワークでボトルネックになることがフロントエンドほど考慮する必要がないため、レスポンスをデータ量多く返しても良い(オーバーフェッチ上等)
-
- GraphQLの層でデータのキャッシュを検討することが出来る
-
- プライベートネットワークからのリクエストに変わるため、セキュリティやパフォーマンスで考慮することを減らせる
- GraphQLアプリケーションはサーバーリソースをコントロール出来るため、スケールアップ・スケールアウトでパフォーマンス制御が可能
以客户为先的API设计
由于服务器端应用程序和数据库通常比前端更稳定,并且难以进行更改,因此不得不采用一种相对通用的API设计。在RESTFul中,存在许多像直接复制数据库表一样的API。然而,这些API并不一定对客户端友好,因为它们考虑了服务器端的需求,导致客户端承受了一定的负担,降低了前端实现的生产力。
但是,GraphQL位于客户端和服务器端之间,可以设计API。API设计不必完全返回数据源返回的响应,GraphQL可以自由设计API。因此,GraphQL可以根据客户端用例进行客户端优先的API设计,以适应客户端。同时,服务器端可以实施服务器端方便的API。通过使用GraphQL,可以减轻客户端和服务器端之间的摩擦。因此,我认为GraphQL可能成为Web API设计的最佳实践。
例: 在北方的冬天,气温常常很低,许多人都会穿厚厚的羽绒服来保暖。
-
- 複数のデータソースから取得したデータを1つのノードとして表現する
-
- 1つのデータソースから取得したデータを複数のノードとして表現する
-
- データソースには存在しない抽象的なデータを表現する
-
- 複数レコードにまたがるデータを1つのノードの1つのフィールドとして配列で表現する
- 配列のデータを複数のノードとして表現する
应用程序和数据存储的易变性
首先让我们回顾一下微服务。虽然这并不是GraphQL的直接优势,但由于在引入GraphQL时通常存在多个服务器端应用程序,所以这是一个常见情况。
一项关于微服务的优点是,可以根据服务内容灵活选择语言、框架和数据源。在使用微服务之前,通常是一次只选择一种语言、应用程序和数据库。因此,人们更倾向于选择通用的、能应付一切的单体架构和关系型数据库。因此,人们过度寄望于单体架构,批评工具的弱点。
自从采用了微服务架构,我们可以根据服务的内容,在适当的位置上灵活地组合多种语言、框架和数据源。
通过采用微服务架构,可以实现以下设计。
-
- 20%しか利用されない80%の機能は開発効率が高い言語・アプリケーションに任せ、80%利用される20%の機能は高速で堅牢に構築出来る言語, ツールで構成されたアプリケーションに任せる等の意思決定が出来る
-
- リレーショナル・データベースで始めたがオブジェクト型のデータベースに保存したほうが良いことが、ある程度運用したあとに発覚したため移行する
- チームの採用状況に応じた言語選択
尽管Microservices可能会将服务细分化,但其本质在于反复进行服务的整合和淘汰。而GraphQL通过对API进行抽象化,促进了Microservices真正的方式,即API的整合和淘汰。
通过采用GraphQL,可以提高服务器端API的易变性,从而可以根据每个时机选择和改变架构设计,以便未来能够乐观地进行设计。这样就可以放心地使用单体架构或根据团队成员的技能组合选择技术。可以说,延迟决定架构设计将成为使用GraphQL的服务器端的一个优点之一。
将经典应用程序进行现代化改编。
在我个人看来,GraphQL不仅仅是为能够掌握现代最新技术的团队而设计的工具,我认为它更是对已经运作了10-20年的经典应用程序而言必不可少的技术。
GraphQL可以以全新的API端点的形式进行创新性的实施和提供,而无需对现有应用程序进行任何更改。因此,即使是使用Java编写的当前系统或者在主机端上运行的COBOL也没有问题。通过实施最新的GraphQL API来封装这些应用程序作为GraphQL应用程序的数据源,并实施使用该API的现代前端应用程序,可以在不进行任何更改的情况下实现现有系统的高可用性和现代应用程序开发。
然后,如果从整个Web应用程序开发市场来看,我认为这个市场可能是最大的。如果将GraphQL和React.js视为一种能够为客户提供现代化Web应用程序而无需更改经典应用程序的技术,那么在日本,它应该有很广泛的应用场景。如果想象一下2020年代通过现代化前端提供银行和公共服务的平庸UI的Web应用程序,不觉得这个市场很火热吗?
我希望未来能看到一些老牌企业使用GraphQL和现代化的前端框架发布现代化的应用程序。
通过使用GraphQL,我们可以总结出服务器端的一些优点。
-
- クライアント都合でのAPIの仕様変更を減らすことが出来る
-
- クライアント都合でのアーキテクチャ変更をする必要がなくなる
-
- クライアントの環境仕様への考慮を減らすことが出来る
-
- フロントエンドの状態管理をApollo Clientが解決した(しそう?)
- Microservicesを採用した場合でのAPI仕様の統一化を図るコストを減らす事が出来る
什么时候应该开始使用GraphQL?
可以想象出一些使用情景。
-
- フロントエンドが複数のデータソースにアクセスしている
-
- フロントエンドで複数のプラットフォームのアプリケーションが存在する
-
- サーバーサイドがMicroservicesで実装されている
-
- 既存のアプリケーションを変更なしにモダンなフロントエンドを実装したい
- フロントエンドでGraphQLを利用して実装したい
我认为前端和后端的情况是不同的。对于前端来说,GraphQL的学习成本比以前的API设计要低,并且Apollo Client的状态管理非常出色,所以我认为可以毫不犹豫地使用它。从后端来看,前端与后端的沟通成本增加之后,才能享受到这些优势,所以我认为在前端多样化和后端多样化开始的时候考虑引入它可能是一个好时机。另外,正如前面所提到的,如果应用程序已经长时间运行,并且需要现代化的前端,我认为考虑使用它是没有损失的。
太长不读(再次提醒)
-
- GraphQLはクライアント側とサーバー側の双方の複雑化を解決するために利用されてる
-
- フロントエンドにとってGraphQLはHTTP上で動く単一の信頼できる唯一のリソースの様に振る舞う
-
- フロントエンドの状態管理のベストプラクティスとしてのApollo Client
-
- クライアントファーストなAPI, GraphQLはWeb APIのベストプラクティスになり得る
- クラシックアプリケーションを改修することなくGraphQLとモダンフロントエンドで今どきのアプリを作れる
最后
GraphQL提供了一些更加便利的功能,比如使用WebSocket进行相互通信的订阅功能,以及ApolloClient的乐观UI等。但出于让更多的人对GraphQL产生兴趣,并且希望引发包括后端人员在内的活跃讨论的目的,我省略了详细介绍这些功能。GraphQL在前端和后端的视角下有不同的表现,这也导致了前端社区和后端社区对它的热情程度可能有所不同。尽管如此,我仍然相信从后端角度来看,根据应用程序的结构和规模,GraphQL可能成为一款救世主级的软件。这次写作也是带着这样的心情进行的。
顺便说一下,我只接触了大约3个月的GraphQL,这篇文章就像是3个月调研的报告一样。在正式开始学习之前,我对GraphQL只是以为它在前端很流行而已。然而,我越是调查,就越觉得这个东西非常有趣,并一直持续到现在。
在我还不理解GraphQL的时候,我带着先入为主的想法觉得又出现了一种新东西,所以我买了一本书来了解它? 如果对GraphQL产生了兴趣,我认为从《入门GraphQL》开始阅读是一个不错的起点。我也是通过阅读这本书,开始思考各种可能性,并在学习过程中获得了这些知识。
所属公司。
我們現在正在株式會社EBILAB開發服務業和餐飲業的數據整合、商業智能(BI)和機器學習服務。在這個過程中,我們需要處理多個數據來源,包括各種數據庫、API、CSV以及以獨有格式保存的數據。我們還需要應對多對多的結構,涉及到WebApp、可穿戴設備、BI工具和機器學習應用等多個客戶端。因為GraphQL非常適合這種情況,所以我們引入了它。目前,EBILAB正在使用Azure、Serverless、Apollo Server、Nuxt.js和Laravel等技術進行開發。如果您對這方面感興趣,請隨時聯繫我們☺️
如果可以的话,请在Twitter上关注一下@saboyutaka,谢谢。