REST 用來(lái)規范應用如何在 HTTP 層與 API 提供方進(jìn)行數據交互 。
REST 描述了 HTTP 層里客戶(hù)端和服務(wù)器端的數據交互規則;客戶(hù)端通過(guò)向服務(wù)器端發(fā)送 HTTP(s)請求,接收服務(wù)器的響應,完成一次 HTTP 交互。這個(gè)交互過(guò)程中,REST 架構約定兩個(gè)重要方面就是 HTTP 請求的所采用方法,以及請求的鏈接。
在請求層面,REST 規范可以簡(jiǎn)單粗暴抽象成以下兩個(gè)規則:
URL 用來(lái)定位資源,跟要進(jìn)行的操作區分開(kāi),這就意味這 URL 不該有任何動(dòng)詞;
下面示例中的 get、create、search 等動(dòng)詞,都不應該出現在 REST 架構的后端接口路徑中。在以前,這些接口中的動(dòng)名詞通常對應后臺的某個(gè)函數。比如:
/api/getUser/api/createApp/api/searchResult/api/deleteAllUsers當我們需要對單個(gè)用戶(hù)進(jìn)行操作時(shí),根據操作的方式不同可能需要下面的這些接口:
/api/getUser (用來(lái)獲取某個(gè)用戶(hù)的信息,還需要以參數方式傳入用戶(hù) id 信息)/api/updateUser (用來(lái)更新用戶(hù)信息)/api/deleteUser (用來(lái)刪除單個(gè)用戶(hù))/api/resetUser (重置用戶(hù)的信息)更有甚者,可能在更新用戶(hù)不同信息時(shí),提供不同的接口,比如:
/api/updateUserName/api/updateUserEmail/api/updateUser這樣的弊端在于:首先加上了動(dòng)詞,肯定是使 URL 更長(cháng)了;其次對一個(gè)資源實(shí)體進(jìn)行不同的操作就是一個(gè)不同的 URL,造成 URL 過(guò)多難以管理。
其實(shí)當你回過(guò)頭看「URL」 這個(gè)術(shù)語(yǔ)的定義時(shí),更能理解這一點(diǎn)。URL 的意思是統一資源定位符,這個(gè)術(shù)語(yǔ)已經(jīng)清晰的表明,一個(gè) URL 應該用來(lái)定位資源,而不應該摻入對操作行為的描述。
在 REST 架構的鏈接應該是這個(gè)樣子:
1. URL 中不應該出現任何表示操作的動(dòng)詞,鏈接只用于對應資源;
2. URL 中應該單復數區分,推薦的實(shí)踐是永遠只用復數;比如 GET /api/users 表示獲取用戶(hù)的列表;如果獲取單個(gè)資源,傳入 ID,比如 /api/users/123 表示獲取單個(gè)用戶(hù)的信息;
3. 按照資源的邏輯層級,對 URL 進(jìn)行嵌套,比如一個(gè)用戶(hù)屬于某個(gè)團隊,而這個(gè)團隊也是眾多團隊之一;那么獲取這個(gè)用戶(hù)的接口可能是這樣:
GET /api/teams/123/members/234 表示獲取 id 為 123 的小組下,id 為234 的成員信息按照類(lèi)似的規則,可以寫(xiě)出如下的接口:
/api/teams (對應團隊列表)/api/teams/123 (對應 ID 為 123 的團隊)/api/teams/123/members (對應 ID 為 123 的團隊下的成員列表)/api/teams/123/members/456 (對應 ID 為 123 的團隊下 ID 為 456 的成員)在很多系統中,幾乎只用 GET 和 POST 方法來(lái)完成了所有的接口操作;這個(gè)行為類(lèi)似于全用 DIV 來(lái)布局。實(shí)際上,我們不只有GET 和 POST 可用,在 REST 架構中,有以下幾個(gè)重要的請求方法:GET,POST,PUT,PATCH,DELETE。這幾個(gè)方法都可以與對數據的 CRUD 操作對應起來(lái)。
CRUD 是指在做計算處理時(shí)的增加(Create)、讀取查詢(xún)(Retrieve)、更新(Update)和刪除(Delete)幾個(gè)單詞的首字母簡(jiǎn)寫(xiě)。即增刪改查
GET /api/users ( 表示讀取用戶(hù)列表)GET 應當實(shí)現為一個(gè)安全方法。用于獲取數據而不應該產(chǎn)生副作用。
POST 是一個(gè)非冪等的方法,多次調用會(huì )造成不同效果;
冪等(Idempotent):如果對服務(wù)器資源的多次請求與一次請求造成的副作用是一樣的的話(huà),那這個(gè)請求方法可以被認為是冪等。
比如下面的請求會(huì )在服務(wù)器上創(chuàng )建一個(gè) name 屬性為 ‘John Snow’ 的用戶(hù);多次請求就會(huì )創(chuàng )建多個(gè)這樣的用戶(hù)。
POST /api/users{ "name": "John Snow"}他們都應當被實(shí)現為冪等方法,即多次同樣的更新請求應當對服務(wù)器產(chǎn)生同樣的副作用。
PUT 和 PATCH 有各自不同的使用場(chǎng)景:
PUT 用于更新資源的全部信息,在請求的 body 中需要傳入修改后的全部資源主體;
而 PATCH 用于局部更新,在 body 中只需要傳入需要改動(dòng)的資源字段。
設想服務(wù)器中有以下用戶(hù)資源 /api/users/123
{ "id": 123, "name": "Original", "age": 20}當我們往后臺發(fā)送更新請求時(shí),PATCH 和 PUT 造成的效果是不一樣。
PUT /api/users/123{ "name": "PUT Update"}上述 PUT 請求操作后的內容是:
{ "id": 123, "name": "PUT Update"}可以觀(guān)察到,資源原有的 age 字段被清除掉了。
而如果改用 PATCH 的話(huà),
PATCH /api/users/123{ "name": "PATCH Update"}更新后的內容是:
{ "id": 123, "name": "PATCH Update", "age": 20}請求中指定的 name 屬性被更新了,而原有的 age 屬性則保持不變。
PATCH 的作用在于如果一個(gè)資源有很多字段,在進(jìn)行局部更新時(shí),只需要傳入需要修改的字段即可。否則在用 PUT 的情況下,你不得不將整個(gè)資源模型全都發(fā)送回服務(wù)器,造成網(wǎng)絡(luò )資源的極大浪費。
DELETE /api/users/123用于刪除服務(wù)器上 ID 為 123 的資源,多次請求產(chǎn)生副作用都是,是服務(wù)器上 ID 為 123 的資源不存在。
REST 風(fēng)格的接口地址,表示的可能是單個(gè)資源,也可能是資源的集合;當我們需要訪(fǎng)問(wèn)資源集合時(shí),設計良好的接口應當接受參數,允許只返回滿(mǎn)足某些特定條件的資源列表。
比如支持以 offset 和 limit 參數來(lái)進(jìn)行分頁(yè);
GET /api/users?offset=0&limit=20支持提供關(guān)鍵詞進(jìn)行搜索,以及排序
GET /api/users?keyword=john&sort=age支持根據字段進(jìn)行過(guò)濾:
GET /api/users?gender=male設計合適的 API URL,以及選擇合適的請求方法,可以語(yǔ)義化的描述一個(gè) HTTP 請求的操作。
當我們都熟悉且遵循這樣的規范后,基本可以看到一個(gè) REST 風(fēng)格的接口就知道如何使用這個(gè)接口進(jìn)行 CRUD 操作了。比如下面這面這個(gè)接口就表示搜索 ID 為 123 的圖書(shū)館的書(shū),并且書(shū)的信息里包含關(guān)鍵字「game」,返回前十條滿(mǎn)足條件的結果。
GET /api/libraries/123/books?keyword=game&sort=price&limit=10&offset=0同樣,下面這個(gè)請求的意思也就很明顯了吧。
PATCH /api/companies/123/employees/234{ "salary": 2300}服務(wù)器向用戶(hù)返回的狀態(tài)碼和提示信息,常見(jiàn)的有以下一些(方括號中是該狀態(tài)碼對應的HTTP動(dòng)詞)。
如果狀態(tài)碼是4xx,就應該向用戶(hù)返回出錯信息。一般來(lái)說(shuō),返回的信息中將error作為鍵名,出錯信息作為鍵值即可。
{ error: "Invalid API key"}針對不同操作,服務(wù)器向用戶(hù)返回的結果應該符合以下規范。
RESTful API最好做到Hypermedia,即返回結果中提供鏈接,連向其他API方法,使得用戶(hù)不查文檔,也知道下一步應該做什么。
比如,當用戶(hù)向api.example.com的根目錄發(fā)出請求,會(huì )得到這樣一個(gè)文檔。
{"link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json"}}上面代碼表示,文檔中有一個(gè)link屬性,用戶(hù)讀取這個(gè)屬性就知道下一步該調用什么API了。rel表示這個(gè)API與當前網(wǎng)址的關(guān)系(collection關(guān)系,并給出該collection的網(wǎng)址),href表示API的路徑,title表示API的標題,type表示返回類(lèi)型。
Hypermedia API的設計被稱(chēng)為HATEOAS。Github的API就是這種設計,訪(fǎng)問(wèn)api.github.com會(huì )得到一個(gè)所有可用API的網(wǎng)址列表。
{ "current_user_url": "https://api.github.com/user", "authorizations_url": "https://api.github.com/authorizations", // ...}從上面可以看到,如果想獲取當前用戶(hù)的信息,應該去訪(fǎng)問(wèn)api.github.com/user , 然后就得到了下面結果。
{ "message": "Requires authentication", "documentation_url": "https://developer.github.com/v3"}關(guān)于 REST 的更多詳細規范,可以參考這個(gè)倉庫。
聯(lián)系客服