不該該使用動詞:python
/getAllResources/createNewResources
git/deleteAllResources
若是要改變資源的狀態,使用PUT、POST、DELETE。下面是錯誤的用GET方法來修改user的狀態:github
GET /users/711?activate GET /users/711/activate
咱們定義資源ticket、user、group:json
GET /tickets # 獲取ticket列表segmentfault
GET /tickets/12 # 查看某個具體的ticketapi
POST /tickets # 新建一個ticketruby
PUT /tickets/12 #新建ticket 12服務器
DELETE /tickets/12 # 刪除ticket 12網絡
只須要一個endpoint:/tickets,再也沒有其餘什麼命名規則和url規則了。app
一個能夠遵循的規則是:雖然看起來使用複數來描述某一個資源看起來特別扭,可是統一全部的endpoint,使用複數使得你的URL更加規整。這讓API使用者更加容易理解,對開發者來講也更容易實現。
處理關聯:
GET /tickets/12/messages # 獲取ticket 12的message列表
GET /tickets/12/messages/5 #獲取ticket 12的message 5
POST /tickets/12/messages 建立ticket 12的一個message
PUT /tickets/12/messages/5 更新ticket 12的message 5
DELETE /tickets/12/messages/5 刪除ticket 12的message 5
/
在url中表達層級,用於按實體關聯關係進行對象導航,通常根據id導航。
過深的導航容易致使url膨脹,不易維護,如 GET /zoos/1/areas/3/animals/4
,儘可能使用查詢參數代替路勁中的實體導航,如GET /animals?zoo=1&area=3
。
url最好越簡短越好,對結果過濾、排序、搜索相關的功能都應該經過參數實現。
過濾:例如你想限制GET /tickets
的返回結果:只返回那些open狀態的ticket, GET /tickets?state=open
這裏的state就是過濾參數。
排序:和過濾同樣,一個好的排序參數應該可以描述排序規則,而不和業務相關。複雜的排序規則應該經過組合實現。排序參數經過 ,
分隔,排序參數前加 -
表示降序排列。
GET /tickets?sort=-priority #獲取按優先級降序排列的ticket列表
GET /tickets?sort=-priority,created_at #獲取按優先級降序排列的ticket列表,在同一個優先級內,先建立的ticket排列在前面。
搜索:有些時候簡單的排序是不夠的。咱們可使用搜索技術來實現
GET /tickets?q=return&state=open&sort=-priority,create_at # 獲取優先級最高且打開狀態的ticket,並且包含單詞return的ticket列表。
有時候API使用者不須要全部的結果,在進行橫向限制的同時(例如值返回API結果的前十個),還應該能夠進行縱向限制,而且這個功能能有效的提升網絡帶寬使用率和速度。可使用fields查詢參數來限制返回的域例如:
GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at
response 的 body直接就是數據,不要作多餘的包裝。錯誤實例:
{ "success":true, "data":{"id":1, "name":"xiaotuan"} }
在POST操做之後,返回201created 狀態碼,而且包含一個指向新資源的url做爲返回頭。
是蛇形命名仍是駝峯命名?若是使用json那麼最好的應該是遵照JavaScript的命名方法-駝峯命名法。Java、C# 使用駝峯,python、ruby使用蛇形。
開啓pretty print返回結果會更加友好易讀,並且額外的傳輸也能夠忽略不計。若是忘了使用gzip那麼傳輸效率將會大大減小,損失大大增長。
經過Accept字段來區分版本號,而不是在url中嵌入版本號: Accept: application/vnd.github.v3+json
Summary Representation
當你請求獲取某一資源的列表時,響應僅返回資源的屬性子集。有些屬性對API來講代價是很是高的,出於性能的考慮,會排除這些屬性。要獲取這些屬性,請求"detailed" representation。
Example:當你獲取倉庫的列表時,你得到的是每一個倉庫的summary representation。
GET /orgs/octokit/repos
Detailed Representation
當你獲取一個單獨的資源時,響應會返回這個資源的全部屬性。
Example:當你獲取一個單獨的倉庫,你會得到這個倉庫的detailed representation。
GET /repos/octokit/octokit.rb
許多API都帶有可選參數。對於GET請求,任何不做爲路徑構成部分的參數均可以經過HTTP查詢參數傳入。
GET https://api.github.com/repos/vmg/redcarpet/issues?state=closed
在這個例子中,'vmg' 和 'redcarpet' 做爲 :owner 和 :repo 的參數,而 :state 做爲查詢參數。
對於POST、PATCH、PUT和DELETE的請求,不包含在URL中的參數須要編碼成JSON傳遞,且 Content-Type爲 'application/json'。
你能夠對根節點GET請求,獲取根節點下的全部API分類。
有三種可能的客戶端錯誤,在接收到請求體時:
1 發送非法JSON會返回 400 Bad Request.
HTTP/1.1 400 Bad Request Content-Length: 35 {"message":"Problems parsing JSON"}
2 發送錯誤類型的JSON值會返回 400 Bad Request.
HTTP/1.1 400 Bad Request Content-Length: 40 {"message":"Body should be a JSON object"}
3 發送無效的值會返回 422 Unprocessable Entity.
HTTP/1.1 422 Unprocessable Entity Content-Length: 149 { "message": "Validation Failed", "errors": [ { "resource": "Issue", "field": "title", "code": "missing_field" } ] }
咱們能夠告訴發生了什麼錯誤,下面是一些可能的驗證錯誤碼:
Error Name | Description |
---|---|
missing | 資源不存在 |
missing_field | 資源必需的域沒有被設置 |
invalid | 域的格式非法 |
already_exists | 另外一個資源的域的值和此處的相同,這會發生在資源有惟一的鍵的時候 |
API v3在合適的地方使用HTTP重定向。客戶端應該假設任何請求都會致使重定向。重定向在響應頭中有一個 Location
的域,此域包含了資源的真實位置。
API v3力爭使用正確的HTTP動詞來表示每次請求。
Verb | Description |
---|---|
HEAD | 對任何資源僅請求頭信息 |
GET | 獲取資源 |
POST | 建立資源 |
PATCH | 使用部分的JSON數據更新資源 |
PUT | 取代資源或資源集合 |
DELETE | 刪除資源 |
不少資源有一個或者更多的 *_url
屬性指向其餘資源。這意味着服務端提供明確的URL,這樣客戶端就沒必要要本身構造URL了。
請求資源列表時會進行分頁,默認每頁30個。當你請求後續頁的時候可使用 ?page
參數。對於某些資源,你能夠經過參數 ?per_page
自定義每頁的大小。
curl 'https://api.github.com/user/repos?page=2&per_page=100'
須要注意的一點是,頁碼是從1開始的,當省略參數 ?page
時,會返回首頁。
關於分頁的其餘相關信息在響應的頭信息的 Link
裏提供。好比,去請求一個搜索的API,查找Mozilla的項目中哪些包含詞彙addClass :
curl -I "https://api.github.com/search/code?q=addClass+user:mozilla"
頭信息中Link字段以下:
Link: <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=2>; rel="next", <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34>; rel="last"
rel="next"
表示下一頁是 page=2
。也就是說,默認狀況下全部的分頁請求都是從首頁開始。rel="last"
提供更多信息,表示最後一頁是34。即咱們還有33頁的信息包含addClass。
總之,咱們應該依賴於Link提供的信息,而不要嘗試本身去猜或者構造URL。
既然已經知道會接收多少頁面,咱們能夠經過頁面導航來消費結果。咱們能夠經過傳遞一個page
參數,例如跳到14頁:
curl -I "https://api.github.com/search/code?q=addClass+user:mozilla&page=14"
這是頭信息中Link字段:
Link: <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=15>; rel="next", <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34>; rel="last", <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=1>; rel="first", <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=13>; rel="prev"
咱們會得到更多的信息,rel="first"
表示首頁,rel="prev"
表示前一頁的頁碼。經過這些信息,咱們能夠構造一個UI界面讓用戶在first、previous、next、last之間進行跳轉。
對於認證的請求,能夠每小時最多請求5000次。對於沒有認證的請求,限制在每小時60次請求。
檢查返回的HTTP頭,能夠看到當前的速率限制:
curl -i https://api.github.com/users/whatever HTTP/1.1 200 OK Server: GitHub.com Date: Thu, 27 Oct 2016 03:05:42 GMT Content-Type: application/json; charset=utf-8 Content-Length: 1219 Status: 200 OK X-RateLimit-Limit: 60 X-RateLimit-Remaining: 48 X-RateLimit-Reset: 1477540017
header頭信息告訴你當前的速率限制狀態:
Header Name | Description |
---|---|
X-RateLimit-Limit | 當前用戶被容許的每小時請求數 |
X-RateLimit-Remaining | 在當前發送窗口內還能夠發送的請求數 |
X-RateLimit-Reset | 按當前速率發送後,發送窗口重置的時間 |
一旦你超過了發送速率限制,你會收到一個錯誤響應:
HTTP/1.1 403 Forbidden Date: Tue, 20 Aug 2013 14:50:41 GMT Status: 403 Forbidden X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1377013266 { "message": "API rate limit exceeded for xxx.xxx.xxx.xxx. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)", "documentation_url": "https://developer.github.com/v3/#rate-limiting" }
全部的API請求必須包含一個有效的 User-Agent
頭。請求頭不包含User-Agent
的請求會被拒絕。
大多數響應都會返回一個 ETag
頭。不少響應也會返回一個 Last-Modified
頭。你可使用這些頭信息對這些資源進行後續請求,分別使用 If-None-Match
和 If-Modified-Since
頭。若是資源沒有發生改變,服務器端會返回 304 Not Modified
。
Limited HTTP Clients
若是你使用的HTTP客戶端不支持PUT、PATCH、DELETE方法,發送一個POST請求,頭信息裏包含X-HTTP-Method-Override字段,它的值是實際須要的動詞。
$ curl -u email:password https://site.enchant.com/api/v1/users/543abc \ -X POST \ -H "X-HTTP-Method-Override: DELETE"
全部響應的頭部包含描述當前限流狀態的字段:
Rate-Limit-Limit: 100 Rate-Limit-Remaining: 99 Rate-Limit-Used: 1 Rate-Limit-Reset: 20
Rate-Limit-Limit
- 當前時間段內容許的總的請求數
Rate-Limit-Remaining
- 當前時間段內還剩餘的請求數
Rate-Limit-Used
- 本次所使用的請求數
Rate-Limit-Reset
- 重置所需秒數
若是速率限制被打破,API會返回 429 Too Many Requests
的狀態碼。在這種狀況下,你的應用不該該再發送任何請求直到 Rate-Limit-Reset
所規定的時間過去。
你能夠本身限制響應返回的域。只須要你傳遞一個 fields
參數,用逗號分隔所須要的域,好比:
GET /api/v1/users?fields=id,first_name
全部返回一個集合的URL,都會提供count統計全部結果的個數。要獲取count值須要加一個 count=true
的參數。count會在消息頭中的Total-Count
字段中返回。
GET /api/v1/tickets?count=true
200 OK Total-Count: 135 Rate-Limit-Limit: 100 Rate-Limit-Remaining: 98 Rate-Limit-Used: 2 Rate-Limit-Reset: 20 Content-Type: application/json
[ ... results ... ]
count表示全部現存結果的數量,而不是這次響應返回的結果的數量。
若是你的HTTP客戶端難以讀取狀態碼和頭信息,咱們能夠將全部都打包進響應消息體中。咱們只須要傳遞參數 envelope=true
,而API會始終返回200的HTTP狀態碼。真正的狀態碼、頭信息和響應都在消息體中。
GET /api/v1/users/does-not-exist?envelope=true
200 OK
{ "status": 404, "headers": { "Rate-Limit-Limit": 100, "Rate-Limit-Remaining": 50, "Rate-Limit-Used": 0, "Rate-Limit-Reset": 25 }, "response": { "message": "Not Found" } }
其餘如 分頁、排序等,enchant的設計規範和GitHub v3大體相同,不在贅述。