让我们逐步了解在处理一些日常用例时涉及的核心 API 概念。
注意:以下指南使用 REST API 进行 GitHub.com。
-
使用
http(s)://[hostname]/api/v3
访问 GitHub Enterprise Server 的 API。 -
指南指定了可能在 您的 GitHub Enterprise Server 实例 上不存在的用户名和仓库。 您可能需要使用不同的名称才能看到类似的输出。
概览
大多数应用程序将使用您选择的语言 中现有的 wrapper 库,但您必须先熟悉基础 API HTTP 方法。
没有比使用 cURL 更容易的入手方式了。
Hello World
让我们先测试设置。 打开命令提示符并输入以下命令:
$ curl https://api.github.com/zen
> Keep it logically awesome.
响应将是我们设计理念中的随机选择。
接下来,我们 GET
Chris Wanstrath 的 GitHub 资料:
# GET /users/defunkt
$ curl https://api.github.com/users/defunkt
> {
> "login": "defunkt",
> "id": 2,
> "node_id": "MDQ6VXNlcjI=",
> "avatar_url": "https://avatars.githubusercontent.com/u/2?v=4",
> "gravatar_id": "",
> "url": "https://api.github.com/users/defunkt",
> "html_url": "https://github.com/defunkt",
> ...
> }
嗯,有点像 JSON。 我们来添加 -i
标志以包含标头:
$ curl -i https://api.github.com/users/defunkt
> HTTP/2 200
> server: GitHub.com
> date: Thu, 08 Jul 2021 07:04:08 GMT
> content-type: application/json; charset=utf-8
> cache-control: public, max-age=60, s-maxage=60
> vary: Accept, Accept-Encoding, Accept, X-Requested-With
> etag: W/"61e964bf6efa3bc3f9e8549e56d4db6e0911d8fa20fcd8ab9d88f13d513f26f0"
> last-modified: Fri, 01 Nov 2019 21:56:00 GMT
> x-github-media-type: github.v3; format=json
> access-control-expose-headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset
> access-control-allow-origin: *
> strict-transport-security: max-age=31536000; includeSubdomains; preload
> x-frame-options: deny
> x-content-type-options: nosniff
> x-xss-protection: 0
> referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
> content-security-policy: default-src 'none'
> x-ratelimit-limit: 60
> x-ratelimit-remaining: 53
> x-ratelimit-reset: 1625731053
> x-ratelimit-resource: core
> x-ratelimit-used: 7
> accept-ranges: bytes
> content-length: 1305
> x-github-request-id: 9F60:7019:ACC5CD5:B03C931:60E6A368
>
> {
> "login": "defunkt",
> "id": 2,
> "node_id": "MDQ6VXNlcjI=",
> "avatar_url": "https://avatars.githubusercontent.com/u/2?v=4",
> "gravatar_id": "",
> "url": "https://api.github.com/users/defunkt",
> "html_url": "https://github.com/defunkt",
>
> ...
> }
响应标头中有一些有趣的地方。 果然,Content-Type
为 application/json
。
任何以 X-
开头的标头都是自定义标头,不包含在 HTTP 规范中。 例如:
X-GitHub-Media-Type
的值为github.v3
。 这让我们知道响应的媒体类型。 媒体类型帮助我们在 API v3 中对输出进行版本控制。 我们稍后再详细讨论。- 请注意
X-RateLimit-Limit
和X-RateLimit-Remaining
标头。 这对标头指示在滚动时间段(通常为一小时)内一个客户端可以发出多少个请求,以及该客户端已使用多少个此类请求。
身份验证
未经身份验证的客户端每小时可以发出 60 个请求。 要每小时发出更多请求,我们需要进行身份验证。 事实上,使用 GitHub Enterprise Server API 做任何有意义的事情需要身份验证。
使用个人访问令牌
使用 GitHub Enterprise Server API 进行身份验证的最简单和最佳的方式是通过 OAuth 令牌使用基本身份验证。 OAuth 令牌包括个人访问令牌。
使用 -u
标志设置您的用户名:
$ curl -i -u your_username http(s)://[hostname]/api/v3/users/octocat
出现提示时,您可以输入 OAuth 令牌,但我们建议您为它设置一个变量:
You can use -u "your_username:$token"
and set up a variable for token
to avoid leaving your token in shell history, which should be avoided.
$ curl -i -u your_username:$token http(s)://[hostname]/api/v3/users/octocat
进行身份验证时,您应该会看到您的速率限制达到每小时 5,000 个请求,如 X-RateLimit-Limit
标头中所示。 除了每小时提供更多调用次数之外,身份验证还使您能够使用 API 读取和写入私有信息。
您可以使用个人访问令牌设置页面轻松创建个人访问令牌。
获取自己的用户个人资料
经过正确的身份验证后,您可以利用与您的 GitHub Enterprise Server 帐户相关联的权限。 例如,尝试获取
$ curl -i -u your_username:your_token http(s)://[hostname]/api/v3/user
> {
> ...
> "plan": {
> "space": 2516582,
> "collaborators": 10,
> "private_repos": 20,
> "name": "medium"
> }
> ...
> }
此时,除了先前为 @defunkt 检索到的公共信息集之外,您还可以查看您的用户个人资料的非公共信息。 例如,您将在响应中看到 plan
对象,它提供有关帐户的 GitHub Enterprise Server 计划的详细信息。
对应用程序使用 OAuth 令牌
需要代表其他用户使用 API 读取或写入私有信息的应用程序应使用 OAuth。
OAuth 使用令牌。 令牌具有两大特点:
- 可撤销访问权限:用户可以随时撤销对第三方应用程序的授权
- 有限访问权限:用户可以在授权第三方应用程序前审查令牌将提供的具体访问权限。
令牌应通过 web 工作流程进行创建。 应用程序将用户发送到 GitHub Enterprise Server 进行登录。 GitHub Enterprise Server 随后显示一个对话框,指示应用程序的名称以及应用程序经用户授权后具有的权限级别。 经用户授权访问后,GitHub Enterprise Server 将用户重定向到应用程序:
像对待密码一样对待 OAuth 令牌!不要与其他用户共享它们,也不要将其存储在不安全的地方。 这些示例中的令牌是假的,并且更改了名称以免波及无辜。
现在我们已经掌握了进行身份验证的调用,接下来我们介绍仓库 API。
仓库
几乎任何有意义的使用 GitHub Enterprise Server 都会涉及到某种程度的仓库信息。 我们可以像之前获取用户详细信息一样 GET
仓库详细信息:
$ curl -i http(s)://[hostname]/api/v3/repos/twbs/bootstrap
同样,我们可以查看经身份验证用户的仓库:
$ curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
http(s)://[hostname]/api/v3/user/repos
或者,我们可以列出其他用户的仓库:
$ curl -i http(s)://[hostname]/api/v3/users/octocat/repos
或者,我们可以列出组织的仓库:
$ curl -i http(s)://[hostname]/api/v3/orgs/octo-org/repos
从这些调用返回的信息将取决于我们进行身份验证时令牌所具有的作用域:
- 具有
public_repo
作用域的令牌返回的响应包含我们在 github.com 上有权查看的所有公共仓库。 - 具有
repo
作用域的令牌返回的响应包含我们在您的 GitHub Enterprise Server 实例 上有权查看的所有公共和私有仓库。
如文档所示,这些方法采用 type
参数,可根据用户对仓库的访问权限类型来过滤返回的仓库。 这样,我们可以只获取直接拥有的仓库、组织仓库或用户通过团队进行协作的仓库。
$ curl -i "http(s)://[hostname]/api/v3/users/octocat/repos?type=owner"
在此示例中,我们只获取 octocat 拥有的仓库,而没有获取她协作的仓库。 请注意上面的引用 URL。 根据您的 shell 设置,cURL 有时需要一个引用 URL,否则它会忽略查询字符串。
创建仓库
获取现有仓库的信息是一种常见的用例,但
GitHub Enterprise Server API 也支持创建新仓库。 要创建仓库,
我们需要 POST
一些包含详细信息和配置选项的JSON。
$ curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
-d '{ \
"name": "blog", \
"auto_init": true, \
"private": true, \
"gitignore_template": "nanoc" \
}' \
http(s)://[hostname]/api/v3/user/repos
在这个最小的示例中,我们为博客(也许要在 GitHub Pages 上提供)创建了一个新的私有仓库。 虽然博客 将是公开的,但我们已经将仓库设置为私有。 在这一步中,我们还将使用自述文件和 nanoc 风格的 .gitignore 模板对其进行初始化。
生成的仓库可在 https://github.com/<your_username>/blog
上找到。 要在您拥有的组织下创建仓库,只需将 API 方法从 /user/repos
更改为 /orgs/<org_name>/repos
。
接下来,我们将获取新创建的仓库:
$ curl -i http(s)://[hostname]/api/v3/repos/pengwynn/blog
> HTTP/2 404
> {
> "message": "Not Found"
> }
哦,不! 它去哪儿了? 因为我们创建仓库为 私有,所以需要经过身份验证才能看到它。 如果您是一位资深的 HTTP 用户,您可能会预期返回 403
。 但由于我们不想泄露有关私有仓库的信息,因此在本例中,GitHub Enterprise Server API 返回 404
,就好像说“我们既不能确认也不能否认这个仓库的存在”。
议题
GitHub Enterprise Server 上的议题 UI 旨在提供“恰到好处”的工作流程,不会妨碍您的其他工作。 通过 GitHub Enterprise Server 议题 API,您可以利用其他工具来提取数据或创建议题,以打造适合您的团队的工作流程。
与 github.com 一样,API 为经过身份验证的用户提供了一些查看议题的方法。 要 查看您的所有议题,请调用 GET /issues
:
$ curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
http(s)://[hostname]/api/v3/issues
要仅获取您的某个 GitHub Enterprise Server 组织下的议题,请调用 GET /orgs/<org>/issues
:
$ curl -i -H "Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4" \
http(s)://[hostname]/api/v3/orgs/rails/issues
我们还可以获取单个仓库下的所有议题:
$ curl -i http(s)://[hostname]/api/v3/repos/rails/rails/issues
分页
一个 Rails 规模的项目有数千个议题。 我们需要分页,进行多次 API 调用来获取数据。 我们来重复上次调用,这次请注意响应标头:
$ curl -i http(s)://[hostname]/api/v3/repos/rails/rails/issues
> HTTP/2 200
> ...
> Link: <http(s)://[hostname]/api/v3/repositories/8514/issues?page=2>; rel="next", <http(s)://[hostname]/api/v3/repositories/8514/issues?page=30>; rel="last"
> ...
Link
标头提供了一种链接到外部资源(在本例中为额外的数据页面)的方法。 由于我们的调用发现的议题超过 30 个(默认页面大小),因此 API 将告诉我们在哪里可以找到结果的下一页和最后一页。
创建议题
我们已经了解如何分页议题列表,现在我们来使用 API 创建议题。
要创建议题,我们需要进行身份验证,因此我们将在标头中传递 OAuth 令牌。 此外,我们还将 JSON 正文中的标题、正文和标签传递到要在其中创建议题的仓库下的 /issues
路径:
$ curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
$ -d '{ \
$ "title": "New logo", \
$ "body": "We should have one", \
$ "labels": ["design"] \
$ }' \
$ http(s)://[hostname]/api/v3/repos/pengwynn/api-sandbox/issues
> HTTP/2 201
> Location: http(s)://[hostname]/api/v3/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": "http(s)://[hostname]/api/v3/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": "http(s)://[hostname]/api/v3/repos/pengwynn/api-sandbox/labels/design"
> }
> ],
> "id": 8356941,
> "assignee": null,
> "state": "open",
> "url": "http(s)://[hostname]/api/v3/repos/pengwynn/api-sandbox/issues/17"
> }
JSON 响应的 Location
响应标头和 url
字段为我们提供了一些新建议题的指示。
条件请求
通过缓存未更改的信息来遵守速率限制,是成为一个良好 API 公民的重要特质。 API 支持条件请求并帮助您正确行事。 请注意我们为获取 defunkt 的个人资料而进行的第一个调用:
$ curl -i http(s)://[hostname]/api/v3/users/defunkt
> HTTP/2 200
> etag: W/"61e964bf6efa3bc3f9e8549e56d4db6e0911d8fa20fcd8ab9d88f13d513f26f0"
除了 JSON 正文之外,还要注意 HTTP 状态代码 200
和 Etag
标头。 ETag 是响应的指纹。 如果我们在后续调用中传递它,则可以告诉 API 仅在资源发生改变的情况才将其再次提供给我们。
$ curl -i -H 'If-None-Match: "61e964bf6efa3bc3f9e8549e56d4db6e0911d8fa20fcd8ab9d88f13d513f26f0"' \
$ http(s)://[hostname]/api/v3/users/defunkt
> HTTP/2 304
304
状态表示该资源自上次请求以来没有发生改变,该响应将不包含任何正文。 另外,304
响应不计入您的速率限制。
耶! 选择您已经了解 GitHub Enterprise Server API 的基础知识!
- 基本 & OAuth 身份验证
- 获取和创建仓库及议题
- 条件请求
继续学习下一个 API 指南 - 身份验证基础知识!