作者: 一字马胡
转载标志 【2017-11-13】
更新日志
日期 | 更新内容 | 备注 |
---|---|---|
2017-11-13 | 新建文章 | 初版 |
导入
作为一种强大的DSQL,学习GraphQL的意义是非常大的,为了迅速了解GraphQL,可以参考文章GraphQL初探:一种强大的DSQL,该文章给出了一个使用GraphQL的简单示例demo。GraphQL不仅可以面向传统的数据库(比如Mysql,NoSql),还可以面向微服务,以及其他的数据源,或者面向数据库、微服务等混合数据源,GraphQL试图抽象服务端的数据成为一个综合的数据库,而前端(客户端)的请求就是查询数据库,这样做很明显的一个好处是前端(客户端)可以根据自己的需要来查询(就像是请求mysql数据库,只输出需要的列),这称为“精准查询”,使用GraphQL的另外一个明显的好处是一次请求即可获取所需要的数据,对于请求REST API来说,每次请求返回的数据格式是相对固定的,没有太多的灵活性,并且可能为了将接口变薄,会根据数据属性等将接口拆分开来,所以每个接口可能只能返回一部分需要的内容,所以就需要客户端来请求多次来获取到所有的数据,这样就造成了一些延时。下面的图片展示了GraphQL如何将多种数据源组合起来为前端(客户端)提供统一的API(使用GraphQL来设计API只需要提供一个端点):
本文依然不会对GraphQL的原理做太多分析总结,学习需要一步一步来,上一篇文章仅仅写了一个可运行的demo,本文想要借助现有的实现来更加深入的了解一些关于GraphQL的内容,为后面可以自主设计GraphQL API提供支持。Github 的V4 API借助了GraphQL来设计,具有很高的研究价值,所以本文就介绍Github 的V4 API,并且介绍如何使用V4接口来从Github的服务器获取我们想要的数据,因为Github V4 API只提供了一个端点:https://api.github.com/graphql,所以很大程度上降低了我们的认知障碍,并且Github提供了在线查询界面:Github V4 API Explorer,你可以在左侧的输入框中输入GraphQL查询语句,点击执行就可以在右侧看到执行结果,非常直观,并且提供了完整的接口文档,可以获取任意我们想要获取的数据,本文将首先介绍一些Github V4 API中的新概念,然后基于Github V4 API Explorer来介绍如何获取我们想要的数据。
Github V4 API中的一些新概念
Schema
首先是Schema,在GraphQL中Schema是一个很重要的概念,Schema定义了GraphQL API的类型系统,它完整的描述了前端(或者客户端)可以从服务端获取的所有数据内容,前端或者客户端的GraphQL查询请求将根据Schema进行校验和执行,客户端可以通过“自省”(introspection)获取关于schema的信息。schema存放于GraphQL API服务器。关于如何生成一个schema可以参考本文开篇的文章链接。
Field
Field是客户端可以从服务端获取的某个内容,比如某个字段,或者某个对象等,GraphQL查询语言本质上就是从对象中选择field,所有的GraphQL操作必须指明到最底层的field,并且返回值为标量,以确保响应结果的结构明白无误,所谓标量(scalar),也就是基本数据类型,比如String、int等。如果你尝试返回一个不是标量的field,schema校验将会抛出错误。你必须添加嵌套的内部field直至所有的field都返回标量,这一点很重要,需要牢牢记住。
Connection
还记得GraphQL的标志吗?它是一个图,由顶点和边构成,所谓Connection,就是可以关联查询,GraphQL就是通过Connection来实现只需要一次请求就可以获取全部需要的数据的功能的,客户端可以通过Connection来进行关联查询,比如在查找一篇文章的信息的时候,除了文章的标题、作者、文字内容、图片内容、阅读数等信息外,可以通过Connection查询该文章下面的评论信息,而在评论中,可以通过Connection根据评论人的id来获取用户的信息,这就是Connection的威力,下文中将会把Connection的威力体现出来。
Edge
Edge是GraphQL中的边,它表示Node之间的Connection,当你查询一个connection时,你通过edge到达node。每个edgesfield都有一个nodefield和一个cursorfield。cursor是用来分页的。
Node
Node是一个对象,它就是我们获取数据的节点,比如用户信息的对象就是一个节点,或者一篇文章的信息就是一个节点,如果正在查询的Node不是标量的话,那么我们需要指定Node中的Field直到返回的是标量类型为止。
Github V4 API实战
上文中介绍了一些关于Github V4 API的相关内容,本文剩下的部分将清楚明白的介绍如何使用Github V4 API来获取我们想要的数据,通过本文的介绍,你应当很清晰的认识到GraphQL带来的福利,以及Github V4 API为何要选择GraphQL来进行设计。首选,你需要打开Github V4 API Explorer,下面的图片展示了你应当看到的界面:
左侧是GraphQL查询语句的输入框,中间是执行结果,右侧是GraphQL查询文档,配合这三个区域,我们可以很方便的获取任意我们想要获取的数据,下面由浅入深的介绍如何从Github获取数据。首先是最简单的一个例子,我想获取当前登录的账号的一些基本信息,包括账号名字,邮箱,id,下面是查询语句:
query {
viewer {
login
url
id
}
}
查询的结果如下:
{
"data": {
"viewer": {
"login": "pandening",
"url": "https://github.com/pandening",
"id": "MDQ6VXNlcjE2MjI1Nzk2"
}
}
}
如果现在我想要获取我的签名呢?只需要在查询语句中增加一个Field就可以了:
query {
viewer {
login
url
id
bio
}
}
返回的结果如下:
{
"data": {
"viewer": {
"login": "pandening",
"url": "https://github.com/pandening",
"id": "MDQ6VXNlcjE2MjI1Nzk2",
"bio": "/╲/\\╭༼ ººل͟ºº ༽╮/\\╱\\"
}
}
}
从返回的结果可以看出,我的登录账号的名字叫做pandening,我的主页url为https://github.com/pandening,id为MDQ6VXNlcjE2MjI1Nzk2,我的签名为“/╲/\╭༼ ººل͟ºº ༽╮/\╱\”(非主流啊),可以发现返回的json和查询的输入是一对一的,这就是所谓的精准查询,不多不少,正好合适。那现在来说说如何写一个查询呢?比如我上面的查询语句是怎么写出来的呢?这就的配合右侧的接口文档了,点开文档可以看到有两种类型的操作,一种是Query,用于查询数据,另外一种是Mutation,用于向服务端发送写请求,本文主要关注的是读数据,也就是Query操作,关于Mutation的相关内容也是类似的。点开Query,我们可以看到下面的内容:
上面我使用了viewer来查询当前登录的Github的信息,所以点开viewer,就可以看到我们可以获取的Field了,如果该Field为标量类型,那么可以直接返回,比如id,如果某个Field不是标量的,比如followers,它就不是一个标量,那么就要一直查询直到返回标量为止。上面的例子很简单,但是通过这个例子可以开始结合接口文档来进行复杂的查询了,下面,有一个需求,需要获取当前账号的名字,url,签名,加入Github的时间,邮箱,以及该账号的前5个followers(账号名、bio、邮箱、加入Github的时间),当前账号的前5个仓库(名字、star信息、fork信息),下面是构造出来的GraphQL查询语句:
query {
viewer {
login
url
bio
email
createdAt
followers(first : 5) {
edges {
node {
name
bio
email
createdAt
}
}
}
repositories(first : 5, isFork : false) {
edges {
node {
name
stargazers (first : 10){
edges {
starredAt
node {
name
}
}
}
forks (first : 10){
edges {
node {
createdAt
name
}
}
}
}
}
}
}
}
返回的结果如下:
{
"data": {
"viewer": {
"login": "pandening",
"url": "https://github.com/pandening",
"bio": "/╲/\\╭༼ ººل͟ºº ༽╮/\\╱\\",
"email": "1425124481@qq.com",
"createdAt": "2015-12-09T14:17:52Z",
"followers": {
"edges": [
{
"node": {
"name": "Wang Weitao",
"bio": "",
"email": "softweitao@126.com",
"createdAt": "2012-10-16T16:02:17Z"
}
},
{
"node": {
"name": "Nthan",
"bio": "",
"email": "664157212@qq.com",
"createdAt": "2013-01-16T02:21:07Z"
}
},
{
"node": {
"name": "Mateusz Bagiński",
"bio": "Python/JavaScript Developer",
"email": "cziken58@gmail.com",
"createdAt": "2013-03-23T12:49:03Z"
}
},
{
"node": {
"name": "Dalin Huang",
"bio": "these violent delights have violent ends",
"email": "dhuan023@gmail.com",
"createdAt": "2014-01-26T20:07:36Z"
}
},
{
"node": {
"name": "Ramsey",
"bio": "Arsenal Fan",
"email": "kiminh@sjtu.edu.cn",
"createdAt": "2014-07-18T13:01:22Z"
}
}
]
},
"repositories": {
"edges": [
{
"node": {
"name": "HJSTL",
"stargazers": {
"edges": [
{
"starredAt": "2016-05-08T04:12:01Z",
"node": {
"name": "Jian Hu"
}
}
]
},
"forks": {
"edges": [
{
"node": {
"createdAt": "2017-01-11T02:14:01Z",
"name": "hjstl"
}
}
]
}
}
},
{
"node": {
"name": "AcppLib",
"stargazers": {
"edges": [
{
"starredAt": "2016-08-21T03:33:14Z",
"node": {
"name": "Jian Hu"
}
}
]
},
"forks": {
"edges": []
}
}
},
{
"node": {
"name": "poj-solution",
"stargazers": {
"edges": [
{
"starredAt": "2016-08-22T12:20:41Z",
"node": {
"name": "Jian Hu"
}
}
]
},
"forks": {
"edges": [
{
"node": {
"createdAt": "2016-12-29T21:18:04Z",
"name": "poj-solution"
}
}
]
}
}
},
{
"node": {
"name": "storm-example-onlineusers",
"stargazers": {
"edges": [
{
"starredAt": "2016-08-22T12:24:23Z",
"node": {
"name": "Jian Hu"
}
}
]
},
"forks": {
"edges": []
}
}
},
{
"node": {
"name": "storm-jsoup-spider",
"stargazers": {
"edges": [
{
"starredAt": "2016-08-24T04:40:58Z",
"node": {
"name": "Jian Hu"
}
}
]
},
"forks": {
"edges": []
}
}
}
]
}
}
}
}
看着很复杂,但是只要照着右侧的GraphQL接口文档就可以快速的组装出我们需要的数据了,当然,你可以组装任意复杂的查询语句,只要符合GraphQL的查询语句的要求,都可以从Github 获取数据,但是需要注意的一点是,GraphQL确实可以一次性获取很全面的数据,但是也需要考虑响应时间的问题,不能一次性获取了大量的数据,但是延时很高,这样的应用的用户体验是很差的,需要权衡一下。
结语
本文是关于GraphQL系列的第二篇文章,主要介绍了Github的V4 API中的一些新概念,以及如何使用V4 API来获取我们想要的数据,文中首先介绍了一个比较简单的查询,然后是一个相对复杂的查询,并且介绍了如何依靠Github提供的GraphQL接口文档来设计自己的GraphQL查询语句,根据Github提供的GraphQL文档,我们可以从Github获取足够复杂的数据。Github的API设计一直以来都是业界的标杆,包括V3的Rest接口,以及V4的GraphQL接口,都值得仔细学习。