讓我們來通過一些核心的 API 概念為我們處理一些日常用例。
大部分應用都會使用你選擇的語言的一個現有 封裝好的庫,但是先熟悉內部的 API HTTP 方法是很重要的。
通過 cURL 來進行試驗是最簡單的。
首先,我們來測試我們的設置是否正確。打開一個命令提示符,輸入下面的命令(不需要 $ 符號)
$ curl https://api.github.com/zen
Keep it logically awesome.
返回的內容將會是我們的設計理念中隨機抽取的一條。
接下來,我們向 Chris Wanstrath's GitHub profile 發(fā)送一個 GET 請求:
# 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",
...
}
Mmmmm,這看起來像 JSON。讓我們添加 -i
參數來包含頭部信息。
$ 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-Type
屬性的值是 application/json
。
每一個以 X-
開頭的頭部都是自定義頭,它們都不包含于 HTTP 標準。讓我們看看其中的幾個:
x-GitHub-Media-Type
的值為 github.v3
。這告訴我們返回值的媒體類型。媒體類型幫助在 API v3 中確定我們的輸出的版本信息。我們將在后面更深入探討。
X-RateLimit-Limit
和 X-RateLimit-Remaining headers
。這一對頭部信息標示出了在一個滾動時間周期內(一般是一個小時)一個客戶端能夠發(fā)起多少請求和這些請求多少已經完成。沒認證的客戶端每小時可以制造60個請求。如果想制造更多,我們需要進行認證。實際上,使用 GitHub API 做任何有趣一點的事情都會要求認證。
GitHub API 最簡單的認證方式是使用你的 GitHub 用戶名和密碼來通過基礎認證。
$ curl -i -u <your_username> https://api.github.com/users/defunkt
Enter host password for user '<your_username>':
這個 -u
參數設置用戶名,cURL 會提示你填寫密碼。你可以使用 -u "username:password"
來避免這個提醒,但這會使你的密碼被記錄在 shell 的歷史記錄中,所以并不推薦這種做法。驗證時,你會看到你的速度限制會升到每小時 5000 個請求,這個會在 X-RateLimit-Limit
頭部信息中標示。
如果你啟用了雙重認證,這個 API 會在以上請求中返回 401 Unauthorized
錯誤碼(其他的 API 請求也一樣):
$ curl -i -u <your_username> https://api.github.com/users/defunkt
Enter host password for user '<your_username>':
HTTP/1.1 401 Unauthorized
X-GitHub-OTP: required; :2fa-type
{
"message": "Must specify two-factor authentication OTP code.",
"documentation_url": "https://developer.github.com/v3/auth#working-with-two-factor-authentication"
}
避免這個錯誤最簡單的方式是創(chuàng)建一個 OAuth 令牌和使用 OAuth 認證,而不是使用簡單的基礎認證。在下面的 OAuth 部分可以看到更詳細的信息。
當認證通過時,你可以利用與 GitHub 賬戶相關聯的權限。例如,嘗試獲取你的用戶配置文件:
$ curl -i -u <your_username> https://api.github.com/user
{
...
"plan": {
"space": 2516582,
"collaborators": 10,
"private_repos": 20,
"name": "medium"
}
...
}
這一次,除了和早先我們獲取 @defunkt 同樣的公共信息集合外,你還將看到你自己用戶配置的非公共信息。比如,你將在返回值看到一個 plan
對象,它給出了賬戶的 GitHub 計劃的細節(jié)。
基本認證雖然方便,但是并不理想,因為你不應該將你的 GitHub 用戶名和密碼共享給任何人。需要通過 API 讀寫另一個用戶的私有信息時必須使用 OAuth。
OAuth 用令牌(token)替代了用戶名和密碼。令牌有兩大特色:
一般來說,令牌能夠通過一個 web 流 來創(chuàng)建。一個應用將用戶跳轉到 Github 登陸。然后 GitHub 會顯示對話框來標明應用的名字,同時也顯示應用曾經被授予的用戶權限。當用戶授權之后,GitHub 會將用戶重定向跳轉回應用:
http://wiki.jikexueyuan.com/project/github-developer-guides/images/oauth_prompt.png" alt="" />
然而,開始使用 OAuth 令牌并不需要你配置整個 web 流。獲取一個令牌的簡單方法是通過個人準入令牌設置頁 創(chuàng)建一個個人準入令牌:
http://wiki.jikexueyuan.com/project/github-developer-guides/images/personal_token.png" alt="" />
同時,授權 API 使得通過基本授權創(chuàng)建一個 OAuth 令牌變得簡單。試試粘貼并運行以下命令:
$ curl -i -u <your_username> -d '{"scopes": ["repo", "user"], "note": "getting-started"}' \
https://api.github.com/authorizations
HTTP/1.1 201 Created
Location: https://api.github.com/authorizations/2
Content-Length: 384
{
"scopes": [
"repo",
"user"
],
"token": "5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4",
"updated_at": "2012-11-14T14:04:24Z",
"url": "https://api.github.com/authorizations/2",
"app": {
"url": "https://developer.github.com/v3/oauth/#oauth-authorizations-api",
"name": "GitHub API"
},
"created_at": "2012-11-14T14:04:24Z",
"note_url": null,
"id": 2,
"note": "getting-started"
}
這個小調用里面包含了很多過程,讓我們來分解一下。首先,-d
標志表明我們正在做一個 POST
調用,使用的是 application/x-www-form-urlencoded
內容類型(和 GET
相對)。所有對 GitHub API 發(fā)起的 POST
請求都必須用 JSON 編寫。
接下來,讓我們看看我們在這個請求播送的 scopes
字段。當創(chuàng)建一個新的令牌時,我們包含了一個可選的數組 scopes,或用來標示這個令牌能夠獲取的信息的準入等級。在這個例子中,我們設置該令牌擁有 repo
權限,這個權限將授予用戶讀寫公共和私有倉庫的權限;該令牌還有 user
域權限,這將授予用戶讀寫公共和私有用戶簡介數據。查看
區(qū)域文檔可以獲得所有區(qū)域的列表。為了避免因可能的侵入行為嚇到用戶,你應該只請求你的應用所實際需要的權限。 201
的狀態(tài)碼告訴我們調用是成功的,并且返回的 JSON 包含了新 OAuth 令牌的詳細信息。
如果你已經打開雙重授權,API 將對上述請求返回前面所述的 401 Unauthorize
錯誤碼。你能夠通過在
X-GitHub-OTP 請求頭 包含一個 2FA OTP 碼來回避這個錯誤:
$ curl -i -u <your_username> -H "X-GitHub-OTP: <your_2fa_OTP_code>" \
-d '{"scopes": ["repo", "user"], "note": "getting-started"}' \
https://api.github.com/authorizations
如果你在一個移動應用打開了 2FA ,可以通過你的手機的一次性密碼獲取一個 OTP 碼。如果你通過短信打開了 2FA,發(fā)起此請求后,你將受到一條包含你的 OTP 碼的短信。
現在,我們能夠在剩下的例子中使用這個40字節(jié)的令牌來替代用戶名和密碼。讓我們再次獲取我們的個人信息,這一次我們使用 OAuth:
$ curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
https://api.github.com/user
請向對待密碼一樣對待 OAuth 令牌!不要和其他用戶分享令牌或者將令牌存儲在不安全的地方。這些例子中的令牌是偽造的,名字也已經修改過,以免影響無關用戶。
現在我們知道了如何進行授權請求,接下來我們來看Repositories API。
幾乎所有有意義的 GitHub API 使用會包含了某種程度的 repositories 信息。我們能夠像我們前面獲取用戶詳細信息一樣獲取 repository 詳情:
$ curl -i https://api.github.com/repos/twbs/bootstrap
用同樣的方式,我們能夠為授權用戶查看 repositories:
$ curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
https://api.github.com/user/repos
或者我們能夠查看另一個用戶的 repositories:
$ curl -i https://api.github.com/users/technoweenie/repos
或者,我們能夠查看一個組織的 repositories:
$ curl -i https://api.github.com/orgs/mozilla/repos
這些調用返回的信息將依賴于我們怎樣被授權的:
repo
域,則將只返回私有 repositories。就像文檔中指出的一樣,這些方法包含了一個 type
參數以便根據用戶對 repository 擁有的訪問權限類型來過濾返回的 repositories。通過這種方式,我們能夠單獨獲取直接擁有的 repositories,組織的 repositories,或者用戶通過一個小組合作的 repositories。
$ curl -i "https://api.github.com/users/technoweenie/repos?type=owner"
在這個例子中,我們獲取了 technoweenie 用戶擁有的 repositories,而不是那些他正在和其他人合作的 repositories。注意上面被引號包括的 URL。依賴于你的 shell 設置, cURL 有時候會要求 URL 被引號包括,否則將忽略查詢字符串。
獲取一個已存在的 repository 的信息是非常常見的應用,但是 GitHub API 也支持創(chuàng)建新的 repositories。為了 創(chuàng)建一個 repository ,我們需要 POST
一些包含細節(jié)和配置選項的 JSON :
$ curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
-d '{ \
"name": "blog", \
"auto_init": true, \
"private": true, \
"gitignore_template": "nanoc" \
}' \
https://api.github.com/user/repos
在這里最小例子里面,我們?yōu)槲覀兊牟┛停赡苁羌茉O在 GitHub Pages )創(chuàng)建了一個新的 repository。 雖然博客將會是公共的,但是我們將 repository 設置為私有的。同樣,在這個請求里,我們用一個 README 文件和一個 nanoc-flavored .gitignore 模板初始化這個 repository。
創(chuàng)建的 repository 將可以在 https://github.com/<your_username>/blog
找到。要創(chuàng)建一個你擁有的組織下的 repository,僅需要修改一個 API 方法,將 /user/repos
變更為 /orgs/<org_name>/repos
。
接下來,讓我們獲取我們新創(chuàng)建的 repository :
$ curl -i https://api.github.com/repos/pengwynn/blog
HTTP/1.1 404 Not Found
{
"message": "Not Found"
}
這是怎么一回事?返回了一個 404
錯誤。因為我們將 repository 設置為私有的,我們需要授權才能查看它。如果你是一個 HTTP 的老用戶,你可能會期望一個 403
而不是 404
。但是因為我們不想泄露私有 repositories 的任何信息,所以 GitHub API 在這種情況下返回一個 404
,表示我們不能確定或者否認這個 repository 的存在。
GitHub Issues UI 目標在于當你遠離你的方向的時候給你提供適合的工作流。通過 GitHub Issues API,你可以使用其他工具提取數據或者創(chuàng)建 Issues 來給你的團隊創(chuàng)建一個工作流。
就像 github.com, 這個 API 給認證用戶提供了一些查看 issues 的方法。查看你的全部 issues,使用 GET/issues
:
$ curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
https://api.github.com/issues
想要獲取你其中一個組織下的 issues,使用 GET /orgs/<org>/issues
:
$ curl -i -H 'Authorization: token 5199831f4dd3b79e7c5b7e0ebe75d67aa66e79d4' \
https://api.github.com/orgs/rails/issues
我們也可以獲取單一 repository 中的全部 issues:
$ curl -i https://api.github.com/repos/rails/rails/issues
一個項目的 Rails 大小擁有上千個 issues。我們將需要進行分頁處理,使用多種 API 來獲取數據。重復最后一條命令,這時候需要注意回復的 headers:
$ curl -i https://api.github.com/repos/rails/rails/issues
HTTP/1.1 200 OK
Link: <https://api.github.com/repos/rails/rails/issues?page=2>; rel="next",
<https://api.github.com/repos/rails/rails/issues?page=14>; rel="last"
Link
的頭部信息將提供一個方法來響應鏈接外部資源,用這種方式來獲取額外頁面的數據。當我們請求獲取超過30條(默認的頁面大?。﹊ssues 的時候,這個 API 將會告訴我們哪里可以獲取下一頁和最后一頁的結果。
我們已經知道怎么將 issues 分頁,現在讓我們使用 API 來創(chuàng)建一個 issue。
要創(chuàng)建一個 issue,我們需要先通過認證,所以在請求的頭部需要傳遞 OAuth 令牌。同時,我們需要傳遞 JSON body 中的 title,body 和 labels 到我們想要創(chuàng)建 issue 的 repository 下面的 /issues
路徑:
$ 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"
}
這個 response 給我們回復了新創(chuàng)建 issue 的一系列指針(pointers),有響應頭的位置
還有 JSON response 的url
域。
作為一個好的api用戶很重要的一點就是緩存信息(從來不改變的)以配合api的速度限制。這個 API 提供條件請求和幫你做正確的事。試想一下我們用來獲取 defunkt’s 配置的第一條命令:
$ curl -i https://api.github.com/users/defunkt
HTTP/1.1 200 OK
ETag: "bfd85cbf23ac0b0c8a29bee02e7117c6"
除了 JSON body,我們注意 HTTP 的狀態(tài)碼200和 ETag 的頭部信息。ETag是 response 的“指紋”。如果我們在隨后的訪問中傳遞它,我們就可以告訴 API 讓它再一次回復之前的 resource,前提是它已經發(fā)生改變。
$ curl -i -H 'If-None-Match: "bfd85cbf23ac0b0c8a29bee02e7117c6"' \
https://api.github.com/users/defunkt
HTTP/1.1 304 Not Modified
狀態(tài)碼304表明這個資源在我們之前訪問到現在時間內都沒有發(fā)生改變,并且這個 response 將不包含 body。作為獎勵,這個304響應將不會影響你的速率限制。
喔!現在我們知道了 GitHub API 的基礎。
繼續(xù)學習下一個 API 指南 身份認證基礎 !