# 利用 GitHub API 学习 GraphQL
GraphQL
GitHub 在 API v4 中选择了 GraphQL,我们可以利用 GitHub 现有的 API 功能来学习 GraphQL 。
# GraphQL (opens new window)是什么?
一种用于 API 的查询语言。
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
# 获取 Token
# 使用 cURL
curl -H "Authorization: bearer 你的token" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" https://api.github.com/graphql
2
3
4
5
返回结果:
{"data":{"viewer":{"login":"Anonymity94"}}}
# 使用 GitHub GraphQL Explorer
使用 GitHub 授权登录即可使用 GitHub 提供的 GraphQL Explorer 功能。
# 查询和变更
# 字段(Fields)
{
viewer {
login
avatarUrl
repositories {
totalCount
}
}
}
2
3
4
5
6
7
8
9
{
"data": {
"viewer": {
"login": "Anonymity94",
"avatarUrl": "https://avatars0.githubusercontent.com/u/13148447?v=4",
"repositories": {
"totalCount": 64
}
}
}
}
2
3
4
5
6
7
8
9
10
11
查询和结果拥有几乎一样的结构。
GraphQL 查询能够遍历相关对象及其字段,使得客户端可以一次请求查询大量相关数据,而不像传统 REST 架构中那样需要多次往返查询。
# 参数(Arguments)
在类似 REST 的系统中,你只能传递一组简单参数 —— 请求中的 query 参数和 URL 段。但是在 GraphQL 中,每一个字段和嵌套对象都能有自己的一组参数,从而使得 GraphQL 可以完美替代多次 API 获取请求。甚至你也可以给 标量(scalar)字段传递参数,用于实现服务端的一次转换,而不用每个客户端分别转换。
{
viewer {
repository(name: "anonymity94.github.io"){
id
name
description
}
}
}
2
3
4
5
6
7
8
9
{
"data": {
"viewer": {
"repository": {
"id": "MDEwOlJlcG9zaXRvcnk0OTM1NTg3OA==",
"name": "Anonymity94.github.io",
"description": "访问地址"
}
}
}
}
2
3
4
5
6
7
8
9
10
11
# 别名(Aliases)
发请求给 GraphQL 服务器时,可以给字段起别名,返回的数据中的对应字段就用这个别名作为属性名。
{
viewer {
userName: login
repository(name: "anonymity94.github.io"){
repositoryId: id
name
description
}
}
}
2
3
4
5
6
7
8
9
10
{
"data": {
"viewer": {
"userName": "Anonymity94",
"repository": {
"repositoryId": "MDEwOlJlcG9zaXRvcnk0OTM1NTg3OA==",
"name": "Anonymity94.github.io",
"description": "访问地址"
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
# 片段(Fragments)
片段: 可复用单元。片段使你能够组织一组字段,然后在需要它们的的地方引入。 片段的 on 后面的字段是接口(Interface)或类(Object)
{
viewer {
...userInfo
}
user(login: "Anonymity94") {
...userInfo
}
}
fragment userInfo on User{
id
name
updatedAt
}
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"data": {
"viewer": {
"id": "MDQ6VXNlcjEzMTQ4NDQ3",
"name": null,
"updatedAt": "2019-08-28T12:09:49Z"
},
"user": {
"id": "MDQ6VXNlcjEzMTQ4NDQ3",
"name": null,
"updatedAt": "2019-08-28T12:09:49Z"
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 操作名称(Operation Name)
操作类型 可以是 query
、mutation
或 subscription
。只有 query
可以省略。
操作名称 是你的操作的有意义和明确的名称。它仅在有多个操作的文档中是必需的,但我们鼓励使用它,因为它对于调试和服务器端日志记录非常有用。GraphQL 的查询和变更名称,以及片段名称,都可以成为服务端侧用来识别不同 GraphQL 请求的有效调试工具。
# 变量(Variables)
query customQuery($login: String!) {
user(login: $login) {
id
name
updatedAt
}
}
2
3
4
5
6
7
Query Variables:
{ "login": "Anonymity94" }
Result:
{
"data": {
"user": {
"id": "MDQ6VXNlcjEzMTQ4NDQ3",
"name": null,
"updatedAt": "2019-08-28T12:09:49Z"
}
}
}
2
3
4
5
6
7
8
9
对于简单参数或固定参数,可以写在查询字符串内。
对于动态或者复杂的参数,我们可以作为分离的字典传进去。变量前缀必须为 $
,后跟其类型。
所有声明的变量都必须是标量、枚举型或者输入对象类型,由 Schema
确定。
变量定义可以是可选的或者必要的。上例中,String
后有有 !
,因此其是必要的。但是如果你传递变量的字段可以为空参数,那变量就是可选的。
# 指令(Directives)
query customQuery($login: String!, $withFollowing: Boolean!) {
user(login: $login) {
id
name
updatedAt
following(first: 10) @include(if: $withFollowing) {
edges {
node {
id
name
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Query Variables:
{
"login": "Anonymity94",
"withFollowing": true
}
2
3
4
{
"data": {
"user": {
"id": "MDQ6VXNlcjEzMTQ4NDQ3",
"name": null,
"updatedAt": "2019-08-28T12:09:49Z",
"following": {
"edges": [
{
"node": {
"id": "MDQ6VXNlcjI0Nzk5Njc=",
"name": "Robin Wieruch"
}
},
{
"node": {
"id": "MDQ6VXNlcjkwNTQzNA==",
"name": "Ruan YiFeng"
}
},
{
"node": {
"id": "MDQ6VXNlcjg0MTYyNQ==",
"name": "老雷"
}
}
]
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
指令可以变量动态地改变我们查询的结构。
一个指令可以附着在字段或者片段包含的字段上,然后以任何服务端期待的方式来改变查询的执行。
GraphQL 支持的指令有两个:
- @include(if: Boolean) 仅在参数为 true 时,包含此字段。
- @skip(if: Boolean) 如果参数为 true,跳过此字段。
尝试修改上面的变量,传递 false
给 withFollowing
,看看结果的变化吧~