推开 GraphQL 大门
一、什么是 GraphQL
官网上说,GraphQL 是一种用于 API 的查询语言。习惯了 REST API,刚开始对这个定义很不理解。再看它的全称:Graph Query Language,图状数据查询语言,这会大体能了解它对图状数据查询应该存在明显的优势。那么 GraphQL 怎么使用呢?如下图所示:
同时,可以看出返回的数据跟请求描述的数据结构是相近的,那么它是否是由客户端自行定义如何去获取 GraphQL API 定义的数据结构?答案:是的,这就是 GraphQL。它存在以下几点特性:
它的接口表述能力够高,查询语法跟查询结果相近,能准确获取数据
GraphQL API 基于类型和字段的方式进行组织,而非入口端点。能够通过单一入口获取所有数据能力。
API 演进无需划分版本,给 GraphQL API 添加字段和类型无需影响现有查询,老旧字段废弃隐藏即可。
获取多个资源,只用一个请求。
https://segmentfault.com/a/1190000014131950
https://www.jianshu.com/p/da1260b95faf
https://www.jianshu.com/p/03a7d390375d
https://blog.csdn.net/ctrip_tech/article/details/98805156
二、GraphQL 应用场景
GraphQL 主要应用场景是在 API 网关,或者说在 BFF 层(Backend For Frontend),用于做服务的聚合。为什么这么说呢?
对于前端多端的场景,可能各端对同一份数据的形态和结构都存在差异,这很大程度加大后端人员的工作量,因此需要减少各端对 API 团队的依赖。
微服务架构下,服务通常根据业务做了领域的细分,再通过搭载 BFF 层对服务数据做聚合管理给前端提供数据,这是 REST 服务常见的操作。但后端人员一方面要理解业务领域模型,同时也要理解页面展示数据需求,当业务越来越庞大,BFF 层聚合能力自身也容易成为瓶颈。
那么,让前端接管 BFF 层做数据的消费,是能够减少数据展示沟通上的成本。但 REST 架构面对业务迭代复杂度过大,版本迭代等问题造成的瓶颈仍需要技术方案来解决。而 GraphQL 恰好是另一种解决思路。举个现实案例,有这么个场景,你需要展示商品详情和商品对应的用户评论,那么在 PC 端你可以不考虑性能问题,让商品详情和商品评论在同一个接口直接返回;但倘若有天接口需要在移动端进行使用,同一个接口返回所有数据过大,会影响性能,这时候你需要将一个接口拆成 2 个接口来解决。这是 REST API 存在的局限性。
三、Schema 和类型系统
GraphQL API 遵循 GraphQL Schema,协议定义了 API 所能支持的操作,包括输入参数和返回内容。该协议是属于强类型的,跟 TypeScript 有些类似。下面看下它的基本类型系统。学过 JavaScript,我们知道它存在基本数据类型和引用类型。GraphQL 的类型也无异于此,分为 Scalar Type(标量类型)和 Object Type(对象类型)。
1. Scalar Type
内建的标量类型有:
String
、Int
、Float
、Boolean
、Enum
,同时它也支持通过Scalar
来声明一个新的标量。标量是整个类型系统中最小的颗粒。
2. Object Type
对象类型用来表述一些复杂抽象的数据模型,比如用户、商品。
上面就声明了一个 User
类型,它存在 3 个字段(Fields),且都对应着标量类型。当然字段也可以对应复杂的对象模型,比如下面:
总之,类型定义可以按照你所需的进行定义它们直接的关联关系。
3. Query 和 Mutation
我们 Scheme 中除了普通对象类型,还存在 Query
和 Mutation
两个特殊类型,它们定义了查询的入口,除此之外他们跟普通对象类型别无二致。
4. Type Modifier
GraphQL 存在 List(用"[]'表示)和 Required(用'!'表示)两种修饰符,一种表示为数组,另一种表示为必须项,不能为空。
了解完 GraphQL 的 Schema 和类型系统,下面用 Node.js 搭建一个 GraphQL 服务。
四、搭建 GraphQL 服务
使用 JavaScript 搭建 GraphQL 服务的方式有很多种,社区也提供了很多支持方案,比如:
直接使用
graphql
库的graphql
和buildSchema
函数可以快速实现借助
apollo-server-express
和express
,这是我司目前采用的通过
express express-graphql graphql
三个库配合实现
当然,能够搭建 GraphQL 服务的实现的方式不仅以上 3 种,下面我们介绍另外一种搭建的方案:
通过graphql-tools
和 express-graphql
搭建,前者负责写协议和解析代码,后者将其连接到 web 服务器。看看 graphql-tools 提供的能力:
生成的协议完全支持解析器、接口、联合和自定义标量,与 GraphQL.js 完全兼容
使用细粒度的每种类型模拟 GraphQL API
自动将多个协议拼接成一个更大的 API
也因为它生成的协议与 GraphQL.js 完全兼容,所以生成的协议其实也是可以在 Apollo GraphQL 中使用。下面开始搭建环境。
1. 创建工程
2. 安装依赖
服务端框架采用 express
,并且采用 typescript
语言编写方便进行类型定义,同时安装对应的graphql
包和它对应的 ts 类型定义。
3. typescript
编译配置
在项目根目录创建 tsconfig.json
配置文件,配置编译输出目录为 build
,同时创建 app.ts
入口文件。
4. 配置 npm scripts
配置完成,便可以通过执行 npm run start
进行项目启动。在 start
命令中,存在 2 条指令:npm run tsc
:该命令是将 typescript 编译成 js 代码。node ./build/app.js
:该命令是用 node 执行 js 脚本文件。这两条命令行是通过 "&&"
操作符连接起来,表示两条命令是串行的关系,只有前面的命令执行结束才会执行后面的命令。那如果需要多条命令并行执行呢?把命令行连接符号改为 "&"
即可。
5. 书写 Hello 服务
在 app.ts 文件中
6. 解析器 Resolvers
协议上定义了 Query 和 Mutation 实际上只进行了一半,实际的核心在于解析器 Resolvers,业务逻辑基本都在这里处理和构造,比如与数据库等交互,它代表着获取数据的真实逻辑。它的命名约定与定义的查询命名一致,因为当接收到一个查询时,会递归解析查询语句,并尝试用对应类型的解析器去获取数据,并将获取的数据给当前的 field。
7. 浏览器访问
浏览器访问服务,在左边输入框输入查询语句,然后点击运行按钮,便返回接口数据了。
关于更复杂的例子,建议自身去尝试。
五、总结
针对 GraphQL 了解它是什么,应用场景在哪,掌握基本用法并且能够搭建环境,至于更复杂的业务场景和实现,实战中去践行吧。
评论