GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
大概率你听说过 GraphQL,知道它是一种与 Rest API 架构属于 API 接口的查询语言。但大概率你也与我一样没有尝试过 GraphQL。
事实上从 2012 年 Facebook 首次将 GraphQL 应用于移动应用,到 GraphQL 规范于 2015 年实现开源。可如今现状是 GraphQL 不温不火,时不时又有新的文章介绍,不知道的还以为是什么新技术。
本文将上手使用 GraphQL,并用 Nestjs 与 Strapi 这两个 Node 框架搭建 GraphQL 服务。
关于 GraphQL 介绍,详见官网 GraphQL | A query language for your API 或相关介绍视频 GraphQL 速览:React/Vue 的最佳搭档
GraphQL 与 Restful API 相比
Restful API
Restful 架构的设计范式侧重于分配 HTTP 请求方法(GET、POST、PUT、PA TCH、DELETE)和 URL 端点之间的关系。如下图
但是实际复杂的业务中,单靠 Restful 接口,需要发送多条请求,例如获取博客中某篇博文数据与作者数据
GET /blog/1
GET /blog/1/author
要么单独另写一个接口,如getBlogAndAuthor
,这样直接为调用方“定制”一个接口,请求一条就得到就调用方想要的数据。但是另写一个getBlogAndAuthor
就破坏了 Restful API 接口风格,并且在复杂的业务中,比如说还要获取博文的评论等等,后端就要额外提供一个接口,可以说非常繁琐了。
有没有这样一个功能,将这些接口做一下聚合,然后将结果的集合返回给前端呢?在目前比较流行微服务架构体系下,有一个专门的中间层专门来处理这个事情,这个中间层叫 BFF(Backend For Frontend)。可以参阅 BFF——服务于前端的后端
但这些接口一般来说都比较重,里面有很多当前页面并不需要的字段,那还有没有一种请求:客户端只需要发送一次请求就能获取所需要的字段
有,也就是接下来要说的 GraphQL
GraphQL
REST API 构建在请求方法(method)和端点(endpoint)之间的连接上,而 GraphQL API 被设计为只通过一个端点,即 /graphql
,始终使用 POST 请求进行查询,其集中的 API 如 http://localhost:3000/graphql,所有的操作都通过这个接口来执行,这会在后面的操作中在展示到。
但是想要一条请求就能得到客户端想要的数据字段,那么服务端必然要做比较多的任务 😟(想想也是,后端啥都不干,前端就啥都能获取,怎么可能嘛)。
而服务端要做的就是搭建一个 GraphQL 服务,这在后面也会操作到,也算是本文的重点。
接下来便会在客户端中体验下 GraphQL,看看 GraphQL 究竟有多好用。
在线体验 GraphQL
可以到 官网 中简单尝试入门一下,在 Studio 可在线体验 GraphQL,也可以到 SWAPI GraphQL API 中体验。
下面以 apollographql
为例,并查询 People 对象。
query
查询所有 People 并且只获取 name
、gender
、height
字段
查询 personID 为 1 的 Person 并且只获取 name
,gender
,height
字段
查询 personID 为 2 的 Person 并且只获取 name
,eyeColor
、skinColor
、hairColor
字段
从上面查询案例中其实就可以发现,我只需要在 person 中写上想要获取的字段,GraphQL 便会返回带有该字段的数据。避免了返回结果中不必要的数据字段。
{
person{
# 写上想获取的字段
}
}
如果你不想要 person 数据或者想要其他其他的数据,不用像 Restful API 那样请求多条接口,依旧请求/graphql
,如
无论你想要什么数据,一次请求便可满足。
mutation
GraphQL 的大部分讨论集中在数据获取(也是它的强项),但是任何完整的数据平台也都需要一个改变服务端数据的方法。即 CRUD。
GraphQL 提供了 变更(Mutations) 用于改变服务端数据,不过 apollographql
在线示例中并没有如 createPeople
字段支持 。这个片段在线体验中就无法体验到,后在后文中展示到。这里你只需要知道 GraphQL 能够执行基本的 CRUD 即可。
fragmen 和 subscribtion
此外还有 fragment
与 subscription
就不做介绍。
小结
尝试完上面这些操作后,可以非常明显的感受到 GraphQL 的优势与便利,本来是需要请求不同的 url,现在只需要请求 /graphql
,对调用方(前端)来说非常友好,香是真的香。
可目前只是使用了别人配置好的 GraphQL 服务,让前端开发用了特别友好的 API。但是,对于后端开发而言,想要提供 GraphQL 服务可就不那么友善了。因为它不像传统的 restful 请求,需要专门配置 GraphQL 服务,而整个过程是需要花费一定的工作量(定义 Schema,Mutations 等等),前面也提到想要一条请求就能得到客户端想要的数据字段,那服务端必然需要额外的工作量。
不仅需要在后端中配置 GraphQL 服务,用于接收 GraphQL 查询并验证和执行,此外前端通常需要 GraphQL 客户端,来方便使用 GraphQL 获取数据,目前实用比较多的是Apollo Graph,不过本文侧重搭建 GraphQL 服务,因此前端暂不演示如何使用 GraphQL。
你可能听过一句话是,graphql 大部分时间在折磨后端,并且要求比较严格的数据字段,但是好处都是前端。把工作量基本都丢给了后端,所以在遇到使用这门技术的公司,尤其是后端岗位就需要考虑有没有加班的可能了。
以下便会开始实际搭建 GraphQL 服务,这里会用 Nest.js 与 Strapi 分别实践演示。
Nest.js
官方文档:GraphQL + TypeScript | NestJS
仓库本文实例代码仓库: kuizuo/nest-graphql-demo
创建项目
nest new nest-graphql-demo
安装依赖
npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express
修改 app.module.ts
import { Module } from '@nestjs/common'
import { GraphQLModule } from '@nestjs/graphql'
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: true,
}),
],
})
export class AppModule {}