天天看點

RESTful 接口實作簡明指南

在前後端分離的 Web 應用架構中,前端專注于頁面,同時與後端進行資料互動;而後端則專注于提供 API 接口。在這樣的結構下,REST 是一個很流行的前後端互動形式的約定。這隻是一套約定,并不是某個技術标準,是以在實際的應用中,對器實作程度完全取決于後端開發者;一些号稱 RESTful 的接口并沒有那麼RESTful。

在我所見過的 RESTful 接口的實作中,以 GitHub 最讓人驚歎。我第一次如此強烈得感受到 REST 接口的美妙,完全滿足了我所期待的「接口的形式美感」,簡直就是對 REST 規範實作的最佳範本。我覺得每一個後端開發者都應該看一看 GitHub 的 REST 接口文檔,感受一下循規蹈矩的美妙。

本文選取了幾個點來簡要介紹,一個讓前端開發者用起來舒服的 RESTful 接口是什麼樣子。

REST 簡介

以防有些觀衆剛剛打開電梯,還是有必要簡單介紹一下 REST 這個概念。

REST 是一個術語的縮寫,REpresentational State Transfer,中文直譯「表征狀态轉移」,這是個很拗口的詞。我的建議是先不要強行了解,直接看怎麼做,等對實施細節有一些了解後,再來看名字會有更深刻的了解。REST 是一套風格約定,RESTful 是它的形容詞形式;比如一套實作了 REST 風格的接口,可以稱之為 RESTful 接口。

REST 對請求的約定

REST 用來規範應用如何在 HTTP 層與 API 提供方進行資料互動;在現階段,你應該已經很熟悉 GET 和 POST 請求;甚至有可能因為受限于後端架構限制等原因,你的整個應用全都是用這兩種 HTTP 方法來完成的。這樣無疑浪費了 HTTP 協定的潛力,而 REST 則充分利用了 HTTP 規範中的方法,達到接口描述的語義化。

REST 描述了 HTTP 層裡用戶端和伺服器端的資料互動規則;用戶端通過向伺服器端發送 HTTP(s)請求,接收伺服器的響應,完成一次 HTTP 互動。這個互動過程中,REST 架構約定兩個重要方面就是 HTTP 請求的所采用方法,以及請求的連結。

在請求層面,REST 規範可以簡單粗暴抽象成以下兩個規則:

  1. 請求 API 的 URL 表示用來定位資源;
  2. 請求的 METHOD 表示對這個資源進行的操作;

以下将以這兩個規則為基礎,描述如何構造一個符合 REST 規範的請求。

一、API 的 URL

URL 用來定位資源,跟要進行的操作區分開,這就意味這 URL 不該有任何動詞;

下面示例中的 get、create、search 等動詞,都不應該出現在 REST 架構的後端接口路徑中。在以前,這些接口中的動名詞通常對應背景的某個函數。比如:

/api/getUser

/api/createApp

/api/searchResult

/api/deleteAllUsers

當我們需要對單個使用者進行操作時,根據操作的方式不同可能需要下面的這些接口:

/api/getUser (用來擷取某個使用者的資訊,還需要以參數方式傳入使用者 id 資訊)

/api/updateUser (用來更新使用者資訊)

/api/deleteUser (用來删除單個使用者)

/api/resetUser (重置使用者的資訊)

更有甚者,可能在更新使用者不同資訊時,提供不同的接口,比如:

/api/updateUserName

/api/updateUserEmail

/api/updateUser

這樣的弊端在于:首先加上了動詞,肯定是使 URL 更長了;其次對一個資源實體進行不同的操作就是一個不同的 URL,造成 URL 過多難以管理。

其實當你回過頭看「URL」 這個術語的定義時,更能了解這一點。URL 的意思是統一資源定位符,這個術語已經清晰的表明,一個 URL 應該用來定位資源,而不應該摻入對操作行為的描述。

在 REST 架構的連結應該是這個樣子:

URL 中不應該出現任何表示操作的動詞,連結隻用于對應資源;

URL 中應該單複數區分,推薦的實踐是永遠隻用複數;比如 GET /api/users 表示擷取使用者的清單;如果擷取單個資源,傳入 ID,比如 /api/users/123 表示擷取單個使用者的資訊;

按照資源的邏輯層級,對 URL 進行嵌套,比如一個使用者屬于某個團隊,而這個團隊也是衆多團隊之一;那麼擷取這個使用者的接口可能是這樣:

GET /api/teams/123/members/234 表示擷取 id 為 123 的小組下,id 為234 的成員資訊

按照類似的規則,可以寫出如下的接口

/api/teams (對應團隊清單)

/api/teams/123 (對應 ID 為 123 的團隊)

/api/teams/123/members (對應 ID 為 123 的團隊下的成員清單)

/api/teams/123/members/456 (對應 ID 為 123 的團隊下 ID 未 456 的成員)

二、API 請求的方法

在很多系統中,幾乎隻用 GET 和 POST 方法來完成了所有的接口操作;這個行為類似于全用 DIV 來布局。實際上,我們不隻有GET 和 POST 可用,在 REST 架構中,有以下幾個重要的請求方法:GET,POST,PUT,PATCH,DELETE。這幾個方法都可以與對資料的 CRUD 操作對應起來。

【Read】 資源的讀取,用 GET 請求;比如:

GET /api/users ( 表示讀取使用者清單)

GET 應當實作為一個安全方法。用于擷取資料而不應該産生副作用。

【Created】資源的建立,用 POST 方法;

POST 是一個非幂等的方法,多次調用會造成不同效果;

幂等(Idempotent):如果對伺服器資源的多次請求與一次請求造成的副作用是一樣的的話,那這個請求方法可以被認為是幂等。

比如下面的請求會在伺服器上建立一個 name 屬性為 'John Snow' 的使用者;多次請求就會建立多個這樣的使用者。

POST /api/users

{

"name": "John Snow"

}

【Update】資源的更新,用于更新的 HTTP 方法有兩個,PUT 和 PATCH。

他們都應當被實作為幂等方法,即多次同樣的更新請求應當對伺服器産生同樣的副作用。

PUT 和 PATCH 有各自不同的使用場景:

PUT 用于更新資源的全部資訊,在請求的 body 中需要傳入修改後的全部資源主體;

而 PATCH 用于局部更新,在 body 中隻需要傳入需要改動的資源字段。

設想伺服器中有以下使用者資源 /api/users/123

"id": 123,

"name": "Original",

"age": 20

當我們往背景發送更新請求時,PATCH 和 PUT 造成的效果是不一樣。

PUT /api/users/123

"name": "PUT Update"

上述 PUT 請求操作後的内容是:

可以觀察到,資源原有的 age 字段被清除掉了。

而如果改用 PATCH 的話,

PATCH /api/users/123

"name": "PATCH Update"

更新後的内容是:

"name": "PATCH Update",

請求中指定的 name 屬性被更新了,而原有的 age 屬性則保持不變。

PATCH 的作用在于如果一個資源有很多字段,在進行局部更新時,隻需要傳入需要修改的字段即可。否則在用 PUT 的情況下,你不得不将整個資源模型全都發送回伺服器,造成網絡資源的極大浪費。

【Delete】資源的删除,相應的請求 HTTP 方法就是 DELETE。這個也應當被實作為一個幂等的方法。如:

DELETE /api/users/123

用于删除伺服器上 ID 為 123 的資源,多次請求産生副作用都是,是伺服器上 ID 為 123 的資源不存在。

三、分頁、過濾

REST 風格的接口位址,表示的可能是單個資源,也可能是資源的集合;當我們需要通路資源集合時,設計良好的接口應當接受參數,允許隻傳回滿足某些特定條件的資源清單。

比如支援以 offset 和 limit 參數來進行分頁;

GET /api/users?offset=0&limit=20

支援提供關鍵詞進行搜尋,以及排序

GET /api/users?keyword=john&sort=age

支援根據字段進行過濾

GET /api/users?gender=male

設計合适的 API URL,以及選擇合适的請求方法,可以語義化的描述一個 HTTP 請求的操作。

當我們都熟悉且遵循這樣的規範後,基本可以看到一個 REST 風格的接口就知道如何使用這個接口進行 CRUD 操作了。比如下面這面這個接口就表示搜尋 ID 為 123 的圖書館的書,并且書的資訊裡包含關鍵字「game」,傳回前十條滿足條件的結果。

GET /api/libraries/123/books?keyword=game&sort=price&limit=10&offset=0

同樣,下面這個請求的意思也就很明顯了吧。

PATCH /api/companies/123/employees/234

"salary": 2300           

總結

限于篇幅限制,本文僅從請求的角度選取了幾個重點描述了實作 RESTful 接口需要滿足的基本要求。關于 REST 的更多詳細規範庫

https://github.com/aisuhua/restful-api-design-references

原文釋出時間為:2018-06-27

本文作者:ioslh

本文來自雲栖社群合作夥伴“

Web項目聚集地

”,了解相關資訊可以關注“

”。

繼續閱讀