大話微服務(三):如何設計Restful API?

API的定義取決於選擇的IPC通信方式,如果是消息機制(如 AMQP 或者 STOMP),API則由消息頻道(channel)和消息類型;如果是使用HTTP機制,則是基於請求/響應(調用http的url),這裡我們先簡述下RestfulAPI的定義。

設計原則

域名

應該儘量將API部署在專用域名之下,如:

也可以放在主域名下:

版本

放入到頭信息的Accept中
制定版本並在版本之間平緩過渡對於設計和維護一套API是個巨大的挑戰。所以,最好在設計之初就使用一些方法來預防可能會遇到的問題。
為了避免API的變動導致用戶使用中產生意外結果或調用失敗,最好強制要求所有訪問都需要指定版本號。請避免提供默認版本號,一旦提供,日後想要修改它會相當困難。
最適合放置版本號的位置URL中,或者是頭信息(HTTP Headers)中在 Accept 段中使用自定義類型(content type)與其他元數據(metadata)一起提交。

提供 Request-Id

為每一個請求響應包含一個Request-Id字段,並使用UUID作為該值。通過在客戶端、服務器或任何支持服務上記錄該值,它能主我們提供一種機制來跟蹤、診斷和調試請求。

路徑

資源名

在RESTful架構中,每個網址代表一種資源(resource),所以網址中不能有動詞,只能有名詞,而且所用的名詞往往與數據庫的表格名對應。一般來說,數據庫中的表都是同種記錄的”集合”(collection),所以API中的名詞也應該使用複數。
舉例來說,有一個API提供動物園(zoo)的信息,還包括各種動物和僱員的信息,則它的路徑應該設計成下面這樣。

行為(Actions)

好的末尾不需要為資源指定特殊的行為,但在特殊情況下,為某些資源指定行為卻是必要的。為了描述清楚,在行為前加上一個標準的actions:

如:

路徑和屬性名

為了和域名命名規則保持一致,使用小寫字母並用-分割路徑名字,例如:

屬性也使用小寫字母,但是屬性名要用下劃線_分割,以便在Javascript中省略引號。 例如:

支持方便的無id間接引用

在某些情況下,讓用戶提供ID去定位資源是不方便的。例如,一個用戶想取得他在Heroku平臺app信息,但是這個app的唯一標識是UUID。這種情況下,你應該支持接口通過名字和ID都能訪問,例如:

不要只接受使用名字而放棄了使用id。

最小化路徑嵌套

在一些有父路徑/子路徑嵌套關係的資源數據模塊中,路徑可能有非常深的嵌套關係,例如:

推薦在根(root)路徑下指定資源來限制路徑的嵌套深度。使用嵌套指定範圍的資源。在上述例子中,dyno屬於app,app屬於org可以表示為:

HTTP動詞

對於資源的具體操作類型,由HTTP動詞表示。
常用的HTTP動詞有下面五個(括號裡是對應的SQL命令):

一些例子:

過濾信息

如果記錄數量很多,服務器不可能都將它們返回給用戶。API應該提供參數,過濾返回結果。
下面是一些常見的參數:

參數的設計允許存在冗餘,即允許API路徑和URL參數偶爾有重複。比如,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。

響應(Responses)

狀態碼

服務器向用戶返回的狀態碼和提示信息,常見的有以下一些(方括號中是該狀態碼對應的HTTP動詞):

提供資源的(UU)ID

在默認情況給每一個資源一個id屬性。除非有更好的理由,否則請使用UUID。不要使用那種在服務器上或是資源中不是全局唯一的標識,尤其是自動增長的id。
生成小寫的UUID格式 8-4-4-4-12,例如:

提供標準的時間戳

為資源提供默認的創建時間 created_at 和更新時間 updated_at,例如:

使用UTC(世界標準時間)時間,用ISO8601進行格式化

在接收和返回時都只使用UTC格式(ISO8601格式的數據)或者使用時間戳。,例如:

錯誤處理

如果狀態碼是4xx,就應該向用戶返回出錯信息。一般來說,返回的信息中將error作為鍵名,出錯信息作為鍵值即可。

返回結果

針對不同操作,服務器向用戶返回的結果應該符合以下規範。

保證響應JSON及最小化

目前為保證響應最小化,一般使用json字符串,並且請求中多餘的空格會增加響應大小,而且現在很多的HTTP客戶端都會自己輸出可讀格式("prettify")的JSON。所以最好保證響應JSON最小化,例如:

而不是這樣:

Hypermedia API

RESTful API最好做到Hypermedia,即返回結果中提供鏈接,連向其他API方法,使得用戶不查文檔,也知道下一步應該做什麼。
比如,當用戶向api.example.com的根目錄發出請求,會得到這樣一個文檔。

上面代碼表示,文檔中有一個link屬性,用戶讀取這個屬性就知道下一步該調用什麼API了。rel表示這個API與當前網址的關係(collection關係,並給出該collection的網址),href表示API的路徑,title表示API的標題,type表示返回類型。
Hypermedia API的設計被稱為HATEOAS。Github的API就是這種設計,訪問api.github.com會得到一個所有可用API的網址列表。

從上面可以看到,如果想獲取當前用戶的信息,應該去訪問api.github.com/user,然後就得到了下面結果。

上面代碼表示,服務器給出了提示信息,以及文檔的網址。

分享自:https://segmentfault.com/a/1190000008697972


分享到:


相關文章: