什么是GraphQL?
首先,GraphQL
来自Facebook,如果你也跟我一样完全没了解过它,不知道它到底是干什么的,那么你一定听说过另一个叫做 Structured QL
的东西。WHAT? 其实就是SQL了。
- 嗯,和
SQL
一样,GraphQL
是一门查询语言(Query Language)
- 同样和
SQL
一样的是,GraphQL
也是一套规范,就像MySQL
是SQL
的一套实现一样,Apollo
,Relay
...也是GraphQL
规范的实现
- 与
SQL
不同的是,SQL
的数据源是数据库,而GraphQL的数据源可以是各种各样的REST API,可以是各种服务/微服务,甚至可以是数据库
这里借Apollo官网的一张图来说明GraphQL在互联网应用架构中所处的位置
几个时间点
- GraphQL规范于2015年开源
- Subscriptions操作于2017年被加入到规范中
那么为什么叫 Graph呢?
Graph是图的意思,在GraphQL
的世界里,万物皆为图,也就是说你可以把你的业务模型建模为图。
图是将很多真实世界现象变成模型的强大工具,因为它们和我们自然的心智模型和基本过程的口头描述很相似。
这里就涉及到了图论,Graph Database之类的知识,感兴趣可以某歌学习一下。
这样我们可以对GraphQL大体有了一个概念了。那么我们来大概了解一下GraphQL。
GraphQL为我们解决了什么问题呢?
简单的说,站在前端角度,很多文章都会提到过为了取代Restful API,稍微具体点:
- API字段的定制化,按需取字段
- API的聚合,一次请求拿到所有的数据
- 后端不再需要维护接口的版本号了
- 完备的类型校验机制,提供了更健壮的接口
在知道以上这些优点是如何做到的之前,我们先来对GraphQL做一个简单的学习
前端学习GraphQL
做为一名前端开发人员,只站在前端的角度上来说,更多的时候,我们需要关心的只有两个操作:
- query: 在GraphQL中这个关键字属于schema(可以理解为协议)中的一种,代表你要执行的是查询动作,即增删改查中的查
- mutation: 代表你要执行的动作是增删改
query
和mutation
统称为schema。其实还有一个subscriptions在2017年被加入到规范(spec)中,让我们可以更轻松的实现推送功能
这里我们以一个公司内部的分享平台的两个场景为例,来介绍一下这两个操作如何使用。
query操作
首先,最基础的一个场景,分享平台首页需要调一个接口,获取全部的分享列表,目前这个接口的调用方式是:
GET /api/share/allShares
返回
{ "shares": [ { "shareId": 1238272, "title": "分享一下Vue3.0", "desc": "Vue3.0就要发布了,带来了哪些新功能呢?", "where": "6F-19会议室", "startTime": 1548842400 }, { "shareId": 1238272, "title": "用flutter写app页面是一种什么样的体验", "desc": "用跨平台框架flutter来写app页面的初体验", "where": "6F-17会议室", "startTime": 1548842400 }, { "shareId": 1238272, "title": "Cordova原理", "desc": "一起来了解一下Cordova", "where": "6F-19会议室", "startTime": 1548842400 } ] }
那么换成GraphQL的方式,我们可以这么写
query { shares { title desc where startTime } }
咦?发现漏掉了一个字段,如果我们要跳至详情页,需要知道分享的id,改造一下
# 给一个查询起一个名字是一个好习惯 query findAllShares { shares { # 为id起了一个别名,叫shareId shareId: id title desc where startTime } }
到此,一个基础的查询操作就完成了。
分页
通常,如果列表类数据量比较大的话,我们会采用分页的方式获取数据,而非一次性获取全部数据,依然以刚才的分享列表获取为例,如果用传统的接口调用的方式,通常是要这样去调接口:
GET /api/share/allShares?star=0&limit=10
返回
{ "allShares": { "totalCount": 3, "shares": [ { "shareId": 1238272, "title": "分享一下Vue3.0", "desc": "Vue3.0就要发布了,带来了哪些新功能呢?", "where": "6F-19会议室", "startTime": 1548842400 }, { "shareId": 1238273, "title": "用flutter写app页面是一种什么样的体验", "desc": "用跨平台框架flutter来写app页面的初体验", "where": "6F-17会议室", "startTime": 1548842400 }, { "shareId": 1238274, "title": "Cordova原理", "desc": "一起来了解一下Cordova", "where": "6F-19会议室", "startTime": 1548842400 } ] } }
我们来继续改造GraphQL的方式,分页的方式:
# 分页方式 query findAllShares($start: Int!, $limit: Int = 10) { allShares (start: $start, limit: $limit) { totalCount shares { shareId: id title desc where startTime } } }
GraphQL提供了完备的分页解决方案,可参考 Pagination
下一场景,得到了所有的分享列表,可以进入详情页了。目前详情页有三个主要的查询接口:获取分享详情,获取分享的评论列表和获取分享者所有的分享列表。如果是传统的方式,我们需要调三个接口:
// 获取分享的详情 GET /api/share/:shareId
// 分享详情返回 { "shareDetail": { "shareId": 1238274, "title": "Cordova原理", "desc": "一起来了解一下Cordova", "where": "6F-19会议室", "startTime": 1548842400, "attchments": "", "creatorId": 321, "lastUpdateTime": 1548842400, "logoUrl": "", ... } }
// 获取分享的评论列表 GET /api/share/comments/:shareId
// 分享评论列表返回 { "commentInfo": { "totalCount": 5, "comments": [ { "id": 1, "content": "非常不错", "userId": 213, "commentTime": 1548842400, }, { "id": 2, "content": "很好", "userId": 214, "commentTime": 1548842400, }, { "id": 3, "content": "不错", "userId": 216, "commentTime": 1548842400, }, { "id": 4, "content": "Very GOOD!", "userId": 2313, "commentTime": 1548842400, } ] } }
// 分享的创建者的创建的全部分享列表 GET /api/share/shares/:creatorId
// 分享创建者的全部分享返回 { "hisShares": [ { "shareId": 1238272, "title": "分享一下Vue3.0", "desc": "Vue3.0就要发布了,带来了哪些新功能呢?", "where": "6F-19会议室", "startTime": 1548842400 }, { "shareId": 1238273, "title": "用flutter写app页面是一种什么样的体验", "desc": "用跨平台框架flutter来写app页面的初体验", "where": "6F-17会议室", "startTime": 1548842400 }, { "shareId": 1238274, "title": "Cordova原理", "desc": "一起来了解一下Cordova", "where": "6F-19会议室", "startTime": 1548842400 } ] }