GitHub chose GraphQL for our API v4 because it offers significantly more flexibility for our integrators. The ability to define precisely the data you want—and only the data you want—is a powerful advantage over the REST API v3 endpoints. GraphQL lets you replace multiple REST requests with a single call to fetch the data you specify.
For more details about why GitHub has moved to GraphQL, see the original announcement blog post.
背景
GraphQL 的核心是一套数据查询语言的规范,是 Facebook 在2012年开发的,2015年开源,Facebook 内部已经广泛应用,用于替代 REST。
GitHub 为什么选择 GraphQL?这是很多用户关心的问题,Github 对此做了解释。
REST 问题所在
首要问题就是扩展性方面,随着 API 的不断发展,会变得越来越臃肿。
REST API 的方式:服务端定义一系列的接口,客户端调用自己需要的接口,获取目标数据进行整合。
例如用户接口,刚开始时,返回的信息会比较少,例如只有: id,name
。
后来用户的信息增加了,就在用户接口中返回更多的信息,例如:id,name,age,city,addr,email,headimage,nick
。
但可能很多客户端只是想获取其中少部分信息,如: name,headimage
,却必须得到所有的用户信息,然后从中提取自己想要的。这个情况会增加网络传输量,并且不便于客户端处理数据。
还有一个不方便的地方,就是客户端在某个需求中,可能需要调用多个独立的 API 才能获取到足够的数据。例如:客户端要显示一篇文章的内容,同时要显示评论、作者信息,那么就可能需要调用文章接口、评论接口、用户接口,这种方式非常不灵活。
GitHub 还遇到其他一些 REST API 不好处理的问题,例如:想要确保客户端提供的参数的类型安全;想要从代码生成文档;想要识别每个端点的 OAuth 请求范围 ……
GraphQL 的优势
GraphQL 简单来说就是:取哪些数据是由客户端来决定。
在 REST 中,给哪些数据是服务端决定的,客户端只能从中挑选,如果 A 接口中的数据不够,那就再请求 B 接口,然后从他们返回的数据中挑出自己需要的。
在 GraphQL 中,客户端直接对服务端说想要什么数据,服务端负责精确的返回目标数据。
例如,你想要获取用户的几个属性信息,你的 GraphQL 请求就是这样的:
{
viewer {
login
bio
location
isBountyHunter
}
}
相应的返回信息是这样的:
{
"data": {
"viewer": {
"login": "octocat",
"bio": "I've been around the world, from London to the Bay.",
"location": "San Francisco, CA",
"isBountyHunter": true
}
}
}
你可以看到 JSON 响应中的键和值与查询字符串中的术语一致。
再看一个复杂的例子,例如你想知道你给多少个项目点亮过星星、最初3个项目的名字、及他们stars、forks、watchers 、open issues 的总数。
GraphQL 请求:
{
viewer {
login
starredRepositories {
totalCount
}
repositories(first: 3) {
edges {
node {
name
stargazers {
totalCount
}
forks {
totalCount
}
watchers {
totalCount
}
issues(states:[OPEN]) {
totalCount
}
}
}
}
}
}
响应:
{
"data":{
"viewer":{
"login": "octocat",
"starredRepositories": {
"totalCount": 131
},
"repositories":{
"edges":[
{
"node":{
"name":"octokit.rb",
"stargazers":{
"totalCount": 17
},
"forks":{
"totalCount": 3
},
"watchers":{
"totalCount": 3
},
"issues": {
"totalCount": 1
}
}
},
{
"node":{
"name":"octokit.objc",
"stargazers":{
"totalCount": 2
},
"forks":{
"totalCount": 0
},
"watchers":{
"totalCount": 1
},
"issues": {
"totalCount": 10
}
}
},
{
"node":{
"name":"octokit.net",
"stargazers":{
"totalCount": 19
},
"forks":{
"totalCount": 7
},
"watchers":{
"totalCount": 3
},
"issues": {
"totalCount": 4
}
}
}
]
}
}
}
}
你只发出了一个请求来获取所需的所有数据。