API的定義取決於選擇的IPC通訊方式,假設是消息機制(如 AMQP 或者 STOMP)。API則由消息頻道(channel)和消息類型。假設是使用HTTP機制,則是基於請求/響應(調用http的url),這裏咱們先簡述下RestfulAPI的定義。html
應該儘可能將API部署在專用域名之下,如:git
https://api.example.com
也可以放在主域名下:github
https://example.org/api/
放入到頭信息的Accept中 制定版本號並在版本號之間平緩過渡對於設計和維護一套API是個巨大的挑戰。因此。最好在設計之初就使用一些方法來預防可能會遇到的問題。 爲了不API的變更致使用戶使用中產生意外結果或調用失敗。最好強制要求所有訪問都需要指定版本號號。請避免提供默認版本號號,一旦提供,往後想要改動它會至關困難。 最適合放置版本號號的位置URL中,或者是頭信息(HTTP Headers)中在 Accept 段中使用本身定義類型(content type)與其它元數據(metadata)一塊兒提交。數據庫
https://api.example.com/v1/
或
Accept: application/vnd.heroku+json; version=3
爲每一個請求響應包括一個Request-Id字段,並使用UUID做爲該值。經過在client、server或不論什麼支持服務上記錄該值。它能主咱們提供一種機制來跟蹤、診斷和調試請求。json
在RESTful架構中,每一個網址表明一種資源(resource),因此網址中不能有動詞。僅僅能有名詞。而且所用的名詞每每與數據庫的表格名相應。通常來講,數據庫中的表都是同種記錄的」集合」(collection),因此API中的名詞也應該使用複數。 舉例來講,有一個API提供動物園(zoo)的信息。還包括各類動物和僱員的信息,則它的路徑應該設計成如下這樣。api
https://api.example.com/v1/zoos https://api.example.com/v1/animals https://api.example.com/v1/employees
好的末尾不需要爲資源指定特殊的行爲,但在特殊狀況下,爲某些資源指定行爲倒是必要的。數組
爲了描寫敘述清楚。在行爲前加上一個標準的actions:架構
/resources/:resource/actions/:action
如:app
/runs/{run_id}/actions/stop
爲了和域名命名規則保持一致。使用小寫字母並用-切割路徑名字。好比:curl
service-api.com/users
service-api.com/app-setups
屬性也使用小寫字母,但是屬性名要用下劃線_切割,以便在Javascript中省略引號。 好比:
service_class: "first"
在某些狀況下,讓用戶提供ID去定位資源是不方便的。好比,一個用戶想取得他在Heroku平臺app信息,但是這個app的惟一標識是UUID。這樣的狀況下,你應該支持接口經過名字和ID都能訪問,好比:
$ curl https://service.com/apps/{app_id_or_name} $ curl https://service.com/apps/97addcf0-c182 $ curl https://service.com/apps/www-prod
不要僅僅接受使用名字而放棄了使用id。
在一些有父路徑/子路徑嵌套關係的資源數據模塊中,路徑可能有很是深的嵌套關係,好比:
/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}
推薦在根(root)路徑下指定資源來限制路徑的嵌套深度。
使用嵌套指定範圍的資源。在上述樣例中,dyno屬於app,app屬於org可以表示爲:
/orgs/{org_id}
/orgs/{org_id}/apps
/apps/{app_id}
/apps/{app_id}/dynos
/dynos/{dyno_id}
對於資源的詳細操做類型,由HTTP動詞表示。 常用的HTTP動詞有如下五個(括號中是相應的SQL命令):
GET(SELECT):從server取出資源(一項或多項)。 POST(CREATE):在server新建一個資源。 PUT(UPDATE):在server更新資源(client提供改變後的完整資源)。 PATCH(UPDATE):在server更新資源(client提供改變的屬性)。 DELETE(DELETE):從server刪除資源。
一些樣例:
GET /zoos:列出所有動物園
POST /zoos:新建一個動物園
GET /zoos/ID:獲取某個指定動物園的信息
PUT /zoos/ID:更新某個指定動物園的信息(提供該動物園的所有信息)
PATCH /zoos/ID:更新某個指定動物園的信息(提供該動物園的部分信息)
DELETE /zoos/ID:刪除某個動物園
GET /zoos/ID/animals:列出某個指定動物園的所有動物
DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物
假設記錄數量很是多。server不可能都將它們返回給用戶。
API應該提供參數。過濾返回結果。
如下是一些常見的參數:
?limit=10:指定返回記錄的數量
?offset=10:指定返回記錄的開始位置。
?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。 ?
sortby=name&order=asc:指定返回結果依照哪一個屬性排序。以及排序順序。 ?animal_type_id=1:指定篩選條件
參數的設計贊成存在冗餘,即贊成API路徑和URL參數偶爾有反覆。
比方,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是一樣的。
server向用戶返回的狀態碼和提示信息,常見的有如下一些(方括號中是該狀態碼相應的HTTP動詞):
200 OK - [GET]:server成功返回用戶請求的數據,該操做是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用戶新建或改動數據成功。
202 Accepted - [*]:表示一個請求已經進入後臺排隊(異步任務)
204 NO CONTENT - [DELETE]:用戶刪除數據成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,server沒有進行新建或改動數據的操做,該操做是冪等的。 401 Unauthorized - [*]:表示用戶沒有權限(令牌、username、password錯誤)。 403 Forbidden - [*] 表示用戶獲得受權(與401錯誤相對),但是訪問是被禁止的。 404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄。server沒有進行操做,該操做是冪等的。 406 Not Acceptable - [GET]:用戶請求的格式不可得(比方用戶請求JSON格式,但是僅僅有XML格式)。 410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再獲得的。
422 Unprocesable entity - [POST/PUT/PATCH] 當建立一個對象時,發生一個驗證錯誤。 500 INTERNAL SERVER ERROR - [*]:server錯誤發生。用戶將沒法推斷髮出的請求是否成功。
在默認狀況給每一個資源一個id屬性。
除非有更好的理由,不然請使用UUID。不要使用那種在server上或是資源中不是全局惟一的標識,尤爲是本身主動增加的id。 生成小寫的UUID格式 8-4-4-4-12,好比:
"id": "01234567-89ab-cdef-0123-456789abcdef"
爲資源提供默認的建立時間 created_at 和更新時間 updated_at,好比:
{
...
"created_at": "2012-01-01T12:00:00Z",
"updated_at": "2012-01-01T13:00:00Z",
...
}
在接收和返回時都僅僅使用UTC格式(ISO8601格式的數據)或者使用時間戳。,好比:
"finished_at": "2012-01-01T12:00:00Z"
或
"timestamp": "1472486035"
假設狀態碼是4xx,就應該向用戶返回出錯信息。通常來講。返回的信息中將error做爲鍵名。出錯信息做爲鍵值就能夠。
{ error: "Invalid API key" }
針對不一樣操做。server向用戶返回的結果應該符合如下規範。
GET /collection:返回資源對象的列表(數組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔
眼下爲保證響應最小化,通常使用json字符串,而且請求中多餘的空格會添加響應大小,而且現在很是多的HTTPclient都會本身輸出可讀格式("prettify")的JSON。
因此最好保證響應JSON最小化。好比:
{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}
而不是這樣:
{
"beta": false,
"email": "alice@heroku.com",
"id": "01234567-89ab-cdef-0123-456789abcdef",
"last_login": "2012-01-01T12:00:00Z",
"created_at": "2012-01-01T12:00:00Z",
"updated_at": "2012-01-01T12:00:00Z" }
RESTful API最好作到Hypermedia,即返回結果中提供連接,連向其它API方法,使得用戶不查文檔,也知道下一步應該作什麼。
比方,當用戶向api.example.com的根文件夾發出請求,會獲得這樣一個文檔。
{"link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" }}
上面代碼表示,文檔中有一個link屬性,用戶讀取這個屬性就知道下一步該調用什麼API了。
rel表示這個API與當前網址的關係(collection關係,並給出該collection的網址),href表示API的路徑,title表示API的標題。type表示返回類型。 Hypermedia API的設計被稱爲HATEOAS。
Github的API就是這樣的設計。訪問api.github.com會獲得一個所有可用API的網址列表。
{
"current_user_url": "https://api.github.com/user",
"authorizations_url": "https://api.github.com/authorizations",
// ...
}
從上面可以看到。假設想獲取當前用戶的信息,應該去訪問api.github.com/user,而後就獲得瞭如下結果。
{
"message": "Requires authentication",
"documentation_url": "https://developer.github.com/v3" }
上面代碼表示,server給出了提示信息,以及文檔的網址。