API 的自助餐 - 是 GraphQL 啦 (初识篇)

GraphQL 是 Facebook 于 2015 年公布的适用于 API 的数据查询语言和环境

它是标准,有着不同社区开发的不同语言的 GraphQL 服务端和客户端实现

目前属于 Linux 基金会下的 GraphQL 基金会

发布至今,GraphQL 并不缺大佬用户们;除了 Facebook 自己在使用 GraphQL,还有 GitHub, Airbnb, Audi, Atlassian, Lyft, PayPal, Pinterest, Starbucks, The New York Times, Yelp… 甚至他们的死对头 Twitter 都在使用 GraphQL

显然,它肯定有什么十分具有魅力的地方,才能吸引到这批在各行各业都有一定地位的巨头们使用

而 GraphQL 最具有魅力的特性之一就是它可以做到数据请求,不多不少,刚刚好

你可以想象一下,普通的 API 就好像点套餐,点到手发现其实你并没有办法吃下这么多东西,这太浪费了!

但是 GraphQL 成为了自助餐,根据你目前的情况决定这食物到底是要还是不要

普通的 API,通常都是一股脑的把所有后端写好的数据传回给你

1
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
{
"character": [
{
"name": "Artoria Pendragon",
"gender": "female",
"type": "Servant",
"class": "Saber",
"va": "川澄 綾子",
"prototype": {
"name": "King Arthur",
"region": "Britain"
}
},
{
"name": "Emiya (Archer)",
"gender": "male",
"type": "Servant",
"class": "Archer",
"va": "諏訪部 順一",
"prototype": {
"name": "Emiya",
"region": "Japan"
}
}
]
}

这是一个很典型的 JSON 数据格式,也是目前最主流的 API 返回格式之一

其中包含了角色的名字,性别,类型,职阶,Voice Actor (VA),和角色原型信息

当前端的开发者只需要到名字和性别的时候,剩下的数据会造成浪费

当然,后端也可以配合前端接受查询参数

例如 query=[name,gender]

这样 API 只返回名字和性别,倒也是一个办法

但是前端或者后端的需求改变,或者需要做出适用于不同客户端的 API,这也会直接面临着 API 的重构

GraphQL 则可以让后端开发完成后,前端根据不同需求,拿取不同数据

在官网中的介绍完美诠释了 GraphQL 最重要的特性

Apps using GraphQL are fast and stable because they control the data they get, not the server.

一个很简单的 GraphQL 查询会像这样

1
2
3
4
5
6
7
8
9
10
{
character {
name
gender
prototype {
name
region
}
}
}

Response 是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"character": [
{
"name": "Artoria Pendragon",
"gender": "female",
"prototype": {
"name": "King Arthur",
"region": "Britain"
}
},
{
"name": "Emiya (Archer)",
"gender": "male",
"prototype": {
"name": "Emiya",
"region": "Japan"
}
}
]
}

GraphQL 在客户端中查询,实际上并不需要特别的库,如果你想,甚至可以用普通的 cURL 或者 JavaScript 中自带的 fetch API 或者开发者常用的 Axios 库

取决于你使用的语言采用的网络请求模块,这对客户端开发者是超级友好的

在官网中,给出了一些范例来向你展示 GraphQL 是如何通过常见的网络请求程序或者模块请求的

cURL

1
2
3
4
curl -X POST \
-H "Content-Type: application/json" \
-d '{"query": "{ hello }"}' \
http://localhost:4000/graphql

{“data”:{“hello”:“Hello world!”}}

又或者 Fetch

1
2
3
4
5
6
7
8
9
10
fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({query: "{ hello }"})
})
.then(r => r.json())
.then(data => console.log('data returned:', data)); // data returned: Object { hello: "Hello world!" }

data returned: Object { hello: “Hello world!” }

我们也开放了一套 GraphQL 的 API demo 接口,有兴趣你可以通过浏览器的开发者工具,在控制台中使用 fetch API 来获取

或者使用你喜爱的 API 调试工具,例如 Postman

更甚至是前面提到的 cURL

不过调试 GraphQL,我个人更加推荐的工具是 Insomnia,它可以自动 fetch GraphQL Endpoint 的文档

不知道为什么,Postman 虽然支持 GraphQL,但是一直不支持抓取 GraphQL API 的文档

地址在: https://fate.jmencrypt.ink/api

API 托管在腾讯云函数服务中,因为函数服务会自动休眠,因此首次访问可能需要一些时间

主要的结构大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
characters: [
{
name
ENname
gender
type
class
va
prototype: {
name
region
}
}
]
1
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
/**
你可以用浏览器的开发者工具把玩把玩

通过调整 {characters} 中要查询的内容,来看看请求回来的结果会发生怎样的变化
**/

fetch('https://fate.jmencrypt.ink/api', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `
query {
characters {
name
ENname
gender
type
class
va
prototype {
name
region
}
}
}`
}),
})
.then(res => res.json())
.then(res => console.log(res.data.characters));

如果你是在手机上,或者对开发者工具不熟悉,也可以点击此处前往我们开发的在线请求演示玩玩

最后,你会拿到一个展开类似于这样的数据

1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
0:
ENname: "Artoria Pendragon"
class: "Saber"
gender: "Female"
name: "アルトリア・ペンドラゴン"
prototype:
name: "King Arthur"
region: "Britain"
__proto__: Object
type: "Servant"
va: "川澄 綾子"
__proto__: Object
1:
ENname: "Emiya (Archer)"
class: "Archer"
gender: "Male"
name: "エミヤ"
prototype:
name: "衛宮士郎"
region: "Japan"
__proto__: Object
type: "Servant"
va: "諏訪部 順一"
__proto__: Object
2:
ENname: "Shirou Emiya"
class: "Master"
gender: "Male"
name: "衛宮士郎"
prototype:
name: "衛宮士郎"
region: "Japan"
__proto__: Object
type: "Master"
va: "杉山 紀彰"
__proto__: Object
3:
ENname: "Rin Tohsaka"
class: "Master"
gender: "Female"
name: "遠坂 凛"
prototype:
name: "遠坂 凛"
region: "Japan"
__proto__: Object
type: "Master"
va: "植田 佳奈"
__proto__: Object
length: 4
__proto__: Array(0)

以上的请求方式完全无需借助第三方的请求模块,再次着重强调 GraphQL 的查询请求实际上无需发生重大改变

对于 GraphQL 的大致介绍就到这里结束了,如果这篇文章的内容引起了你对 GraphQL 的兴趣,并且想实践一下,我推荐你可以去看看 GraphQL 的官网;他们具有完整的 GraphQL 入门教程,帮助你了解 GraphQL 的类型系统,参数,变更等等更加高级的功能。如果你在使用 NodeJS 和 Express,有个好消息,官网也有 express-graphql 的教程手把手带你从普通的 Express 变到支持 GraphQL 标准的 Express 服务器

English: https://graphql.org/

中文 (简体): https://graphql.cn/