GraphQL实战
1. GrqphQL是什么
GraphQL是一种面向数据的API查询风格。
GraphQL是由Facebook主导开发的一款面向数据的API查询语言。客户端只需给他一个描述,然后GraphQL就能从数据库组合出符合描述的数据并返回。
2. GraphQL解决了什么问题
在开发中我们一般都使用的是RESTful API,它是是面向资源的。通常渲染一个页面我们需要多个资源,REST API请求多个资源时就会载入多个URL,而GraphQL可以通过一次请求就可以获取到需要的所有数据。
解决痛点:
-
接口返回数据格式并不是调用者(前端)理想型
-
多个资源只用一个请求,减少服务器压力
-
数据字段由调用者控制
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
示例:
这里以掘金的首页举例,它可能分为这几个资源(文章列表,分类列表,作者榜)
REST API
文章列表/articles
[
{
title: 'xxx',
content: 'xxx内容'
}
]
分类列表/categories
[
{
id: '1'
name: '前端',
},
{
id: '2'
name: '后端',
},
]
作者推荐榜/recommendationAuthor
[
{
id: 1,
username: '张三'
}
]
上面是用REST接口来获取首页需要的数据,需要发送3次请求,再看下GraphQL的请求是什么样?
GraphQL查询接口/graphql/query
query getHomePage() {
articleList($first: 0) {
title
content
},
categoryList(){
id
name
},
recommendationAuthorList($limit: 10) {
id
username
},
}
通过Graphql只用请求一次就可以拿到全部信息,返回的数据格式都是由调用者控制的,不多不少。
3 GraphQL重要概念
这里先介绍几个GraphQL比较重要的概念,可以参考着GraphQL官网文档看。
3.1 操作类型
操作类型可以是query、mutation、substription ,描述你打算做什么类型的操作。
- query 查询
- mutation 变更
- substription 订阅,当数据更新后,会推送消息
每一个Graphql都有一个query
类型,也可能有一个mutation
类型。他们定义了每一个Graphql查询的入口。
3.2 标量类型
- Int
有符号32位整数
- Float
有符号双精度浮点数
- String
UTF-8字符序列
- Boolean
true或者false
- ID
ID标量类型标识一个唯一标识符
3.3 对象类型和字段
type Article{
title: String
author: [User]
}
上面我声明了一个GraphQL对象类型,这里声明了两个字段并指定了字段类型。
String是内置的标量类型之一,查询中无法对他进行次级选择。
[User] 表示一个User数组,数组中的每个项目都是一个User对象。
-
User对象怎么来的呢?
如Article一样 使用
type
关键字声明type User { name: String age: Int }
-
声明对象有什么用?
通过Query对外提供查询入口时,我们通常都是以一个对象为一个单位。可以把每个对象看作成一个接口。
3.3 输入类型
通过Mutation对外提供变更入口。有时你需要传递一整个对象作为新建对象,之前的标量类型就不能满足了。
官网示例:
4. egg-graphql实战
客户端使用前,我们需要在服务端定义Schema结构。
4.1 使用脚手架生成Egg项目
PS: 下载太慢时可以先全局安装egg-init脚手架,再执行egg-init --type simple --registry china
使用淘宝镜像生成项目
4.2 安装graphql插件
-
执行
npm i egg-apollo-server --save
-
在egg项目中添加graphql的相关配置, 详见egg-apollo-server
这里我没有用egg-graphql插件而使用的是egg-apollo-server
PS:config.graphql.subscriptions用来对grapql请求做鉴权的,在此demo里不需要改为false即可
4.3 定义schema
├── app
│ ├── controller
│ │ └── home.js
│ ├── graphql
│ │ ├── article
│ │ │ ├── resolver.js
│ │ │ └── schema.graphql
│ ├── router.js
│ └── service
├── config
│ ├── config.default.js
│ └── plugin.js
├── package.json
└── package-lock.json
-
schema.graphql
定义GraphQL类型和操作
extend type Query { articleList(first: ID): [Article] } type Article { id: ID title: String content: String author: Author } type Author { name: String age: Int } extend type Mutation { addArticle(title: String, content: String, author: AddAuthor): Article } input AddArticle { title: String content: String } input AddAuthor { name: String age: Int }
-
resolver.js
实现操作
'use strict'; const list = [ { id: 1, content: 'aaa', title: '', author: { name: 'aaa', age: 18, }, }, { id: 2, content: 'bbb', title: '', author: { name: 'aaa', age: 18, }, }, ]; module.exports = { Query: { articleList: () => { return list; }, }, Mutation: { addArticle(root, params, ctx) { console.log(params); params.id = list.length++; list.push(params); return params; }, }, };
4.4 graphql调试
浏览器打开 http://127.0.0.1:7001/graphql 进行调试
PS: 测试前需要关闭csrf保护,否则调试发送的post请求将会被拦截
左侧为查询区,在这里写操作语句。右侧为执行结果。
查询调试
{
articleList(first: 0){
id
title
content
author{
name
age
}
}
}
变更调试
mutation {
addArticle(title: "title", content: "content", author: {name: "张三", age: 15}){
title
content
id
}
}