0%

【译】GitHub API 手册(一):起步

按照惯例,让我们过一遍API的核心概念吧。

概览

大多数应用都会在你所熟悉的语言中存在一款封装库,但重要的是你得熟悉这些API底层的HTTP方法。

如何你打算使用其它客户端的话,没什么比cURL更好用的轮子了,注意在你发起请求的时候必须先发送有效的User Agent Header

Hello World

来不及解释了快上车吧!打开你的命令行终端并敲下如下指令:

1
2
curl https://api.github.com/zen
Keep it logically awesome.

上述的响应是从我们的设计理念中随机节选的。

然后,让我们GET一下Chris WanstrathGithub profile吧:

1
2
3
4
5
6
7
8
9
# GET /users/defunkt
curl https://api.github.com/users/defunkt
{
"login": "defunkt",
"id": 2,
"url": "https://api.github.com/users/defunkt",
"html_url": "https://github.com/defunkt",
...
}

哟~~~看着像是JSON嘛。在刚刚的命令里加个-i标志看看它所包含的头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
curl -i https://api.github.com/users/defunkt
HTTP/1.1 200 OK
Server: GitHub.com
Date: Sun, 11 Nov 2012 18:43:28 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Status: 200 OK
ETag: "bfd85cbf23ac0b0c8a29bee02e7117c6"
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1352660008
X-GitHub-Media-Type: github.v3
Vary: Accept
Cache-Control: public, max-age=60, s-maxage=60
X-Content-Type-Options: nosniff
Content-Length: 692
Last-Modified: Tue, 30 Oct 2012 18:58:42 GMT
{
"login": "defunkt",
"id": 2,
"url": "https://api.github.com/users/defunkt",
"html_url": "https://github.com/defunkt",
...
}

貌似有个小东西藏在里面,注意看,Content-Typeapplication/json

任何以X-开头的都表示自定义头,非HTTP协议规定。例如:

认证

未认证的客户端能够每小时发起60次请求。若想要每小时发起更多请求,我们就需要认证了。事实上,你想要用GitHub API进行任何“嘿嘿嘿”的操作前都必须经过认证

使用personal access tokens

GitHub API最简单好用的认证方式莫过于OAuth令牌的基本认证。OAuth令牌包括个人访问令牌

-u标志位设置你的用户名:

1
curl -i -u your_username https://api.github.com/users/octocat

根据提示,你可以创建出OAuth令牌,但我们更推荐你将其设置为可变的:

你可以通过-u "username:$token"并设置一个token环境变量以避免其暴露在shell历史命令中,尽量避免这种情况。

1
curl -i -u username:$token https://api.github.com/users/octocat

认证成功后,你会看到请求限制率猛增到每小时5000次,主要在X-RateLimit-Limit头中体现。当然,认证后除了每小时更多次请求外,你还可以使用API读写私有信息。

你可以在你的个人访问令牌设置页面轻松地创建一个个人访问令牌

获取属于你自己的用户资料

认证成功后,你就拥有了GitHub账户的高级许可。例如,试试获取你的用户资料

1
2
3
4
5
6
7
8
9
10
11
curl -i -u your_username:your_token https://api.github.com/user
{
...
"plan": {
"space": 2516582,
"collaborators": 10,
"private_repos": 20,
"name": "medium"
}
...
}

这次,我们省略了有关@defunkt的公开信息,你应该能够看到类似上边的你的用户资料。例如,你会看到响应中的plan节点,提供了有关GitHub账户的计划细节。

使用OAuth tokens for apps

若要在APP端以不同用户名义通过API读写私有信息的话应该采用OAuth

OAuth使用的是令牌。令牌提供两大特性:

  • 访问撤销:用户可以在任何时候撤销第三方APP的认证
  • 访问限制:用户可以在提供第三方APP认证前审查每个令牌的访问规则。

令牌应该通过Web流创建。一个应用向GitHub发起用户登录。GitHub会给出对话框提示APP的名称,以及它被用户授权后的访问级别。当用户授权访问后,GitHub会将用户重定向到此应用。

对待OAuth令牌应该像对待密码一样!不要将其共享给其他用户或存储到不安全的地方。这些令牌应该在你做完这些例程后被作废,其命名也要修改。

现在,有关认证的内容,让我们踩下刹车,移步到有关仓库API,上车吧!

仓库

几乎任何一种有意义的GitHub API使用都会涉及到仓库信息的一些级别。我们可以通过类似拉取用户细节的方式去GET仓库细节

1
curl -i https://api.github.com/repos/twbs/bootstrap

同样地,我们可以为认证用户查阅仓库

1
2
curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
https://api.github.com/user/repos

或者,我们可以向其他用户展示仓库列表

1
curl -i https://api.github.com/users/octocat/repos

或者,我们可以向组织机构展示仓库列表

1
curl -i https://api.github.com/orgs/octo-org/repos

这些请求的反馈信息依赖于我们在认证时令牌的访问范围:

  • 一个public_repo范围的令牌会返回一个包含github.com所能够看到的全部公开仓库的响应。
  • 一个带有repo范围的令牌会返回一个包含github.com所能够看到的全部公开和私有仓库的响应。

如下文所示,这些方法都可以通过type参数,根据用户对仓库的访问类型对这些返回的仓库进行过滤。通过这种方式,我们就可以拉取仅是直属仓库、组织仓库、或者是用户合作团队的仓库。

1
curl -i "https://api.github.com/users/octocat/repos?type=owner"

在这个例子中,我们抓取了仅octocat所拥有的仓库,而非她合作团队的。注意上边URL的引号。这部分取决于你安装的shell软件,cURL有时候需要将URL引起来,否则它就会把后边的查询字符串忽略掉。

创建一个仓库

拉取已有的仓库信息只是一个普通用例,GitHub API也支持新建仓库。为了创建仓库,我们要POST一些含有细节和配置的JSON语句:

1
2
3
4
5
6
7
8
curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
-d '{ \
"name": "blog", \
"auto_init": true, \
"private": true, \
"gitignore_template": "nanoc" \
}' \
https://api.github.com/user/repos

在上述的小例子中,我们新建了一个博客仓库(或许可以…将其用在GitHub Pages)。尽管博客是公开的,我们也可以把仓库变成私有的。在这一步骤中,我们也可以连同README、nanoc.gitignore template一并初始化。

在此之后,该仓库需要在https://github.com/<your_username>/blog才能被看到。若是在组织机构下创建的仓库,其API也需要从/user/repos变为/orgs/<org_name>/repos

下一步,让我们拉取刚才创建的仓库吧:

1
2
3
4
5
curl -i https://api.github.com/repos/pengwynn/blog
HTTP/1.1 404 Not Found
{
"message": "Not Found"
}

阿咧~跑哪去了?哦,刚才我们把仓库设置成私有了,需要认证后才能看到它。如果你是个会哭的HTTP小孩,你可能希望有403吃。但我们并不希望泄露任何私有仓库的信息,所以GitHub API在这里返回的是404,就当我们在说“我即不肯定也不否定仓库的存在。”

问题

GitHub对问题的UI旨在提供是“刚刚够”的工作流,同时又不会干扰到你。通过GitHub的Issues API,你可以通过其它工具拉取数据或创建问题以为你的团队创建一种工作流。

正如github.com,API提供了一些简单的方法以给认证用户查看issues。若要查看所有你的issues,请调用GET /issues

1
2
curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
https://api.github.com/issues

若仅是获取你所属GitHub组织的issues,请调用GET /orgs/<org>/issues

1
2
curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
https://api.github.com/orgs/rails/issues

我们也可以获取一个仓库的所有issues

1
curl -i https://api.github.com/repos/rails/rails/issues

分页

一个标杆级的项目会有数千个issues。我们就需要分页了,而且需要调用多个API后才能拿到数据。让我们重复最近因此请求,这次请留意响应头:

1
2
3
4
5
curl -i https://api.github.com/repos/rails/rails/issues
HTTP/1.1 200 OK
...
Link: <https://api.github.com/repositories/8514/issues?page=2>; rel="next", <https://api.github.com/repositories/8514/issues?page=30>; rel="last"
...

这个Link提供了一种扩展资源链接的响应方式,作为本页的其它数据页面。经过我们的调用发现有超过30个问题(默认页面数),这个API告诉我们下一页和上一页分别在哪里。

创建一个问题

现在我们知道了问题列表如何分页,让我们通过API创建一个问题吧

为了创建问题,我们先要经过认证,因此我们会在header中传递一个OAuth令牌。同时,我们还会在想要创建问题的仓库的/issues路径下,通过JSON消息传递title、body、labels等。

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
curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
-d '{ \
"title": "New logo", \
"body": "We should have one", \
"labels": ["design"] \
}' \
https://api.github.com/repos/pengwynn/api-sandbox/issues

HTTP/1.1 201 Created
Location: https://api.github.com/repos/pengwynn/api-sandbox/issues/17
X-RateLimit-Limit: 5000
{
"pull_request": {
"patch_url": null,
"html_url": null,
"diff_url": null
},
"created_at": "2012-11-14T15:25:33Z",
"comments": 0,
"milestone": null,
"title": "New logo",
"body": "We should have one",
"user": {
"login": "pengwynn",
"gravatar_id": "7e19cd5486b5d6dc1ef90e671ba52ae0",
"avatar_url": "https://secure.gravatar.com/avatar/7e19cd5486b5d6dc1ef90e671ba52ae0?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png",
"id": 865,
"url": "https://api.github.com/users/pengwynn"
},
"closed_at": null,
"updated_at": "2012-11-14T15:25:33Z",
"number": 17,
"closed_by": null,
"html_url": "https://github.com/pengwynn/api-sandbox/issues/17",
"labels": [
{
"color": "ededed",
"name": "design",
"url": "https://api.github.com/repos/pengwynn/api-sandbox/labels/design"
}
],
"id": 8356941,
"assignee": null,
"state": "open",
"url": "https://api.github.com/repos/pengwynn/api-sandbox/issues/17"
}

响应里给出了一对指向于最新创建的issue,包括响应头中的Location和响应JSON中的uel域。

其它请求

要成为一名API良民很大一部分是通过缓存未更新的信息来遵守rate limits。API支持条件请求以及帮你做正确的事。回想一下最开始我们获取defunkt的个人资料的调用:

1
2
3
curl -i https://api.github.com/users/defunkt
HTTP/1.1 200 OK
ETag: "bfd85cbf23ac0b0c8a29bee02e7117c6"

除JSON消息体之外,留意一下HTTP的状态码200以及ETag头。ETag是一种响应指纹。若我们随后的调用通过了,我们可以告诉API在资源发生变化时再给我们:

1
2
3
curl -i -H 'If-None-Match: "bfd85cbf23ac0b0c8a29bee02e7117c6"' \
https://api.github.com/users/defunkt
HTTP/1.1 304 Not Modified

304状态码表示该资源与上次询问相比并未发生改变,响应种也不会包含消息体。作为好处,304的响应不会统计到你的rate limit中。

呀呵!现在你已经基本掌握GitHub API了!

  • 基础 & OAuth认证
  • 拉取 & 创建仓库和问题
  • 条件请求
小小鼓励,大大心意!