在先後端分離的 Web 應用架構中,前端專一於頁面,同時與後端進行數據交互;然後端則專一於提供 API 接口。在這樣的結構下,REST 是一個很流行的先後端交互形式的約定。這只是一套約定,並非某個技術標準,因此在實際的應用中,對器實現程度徹底取決於後端開發者;一些號稱 RESTful 的接口並無那麼RESTful。前端
在我所見過的 RESTful 接口的實現中,以 GitHub 最讓人驚歎。我第一次如此強烈得感覺到 REST 接口的美妙,徹底知足了我所期待的「接口的形式美感」,簡直就是對 REST 規範實現的最佳範本。我以爲每個後端開發者都應該看一看 GitHub 的 REST 接口文檔,感覺一下循規蹈矩的美妙。git
本文選取了幾個點來簡要介紹,一個讓前端開發者用起來舒服的 RESTful 接口是什麼樣子。github
以防有些觀衆剛剛打開電梯,仍是有必要簡單介紹一下 REST 這個概念。後端
REST 是一個術語的縮寫,REpresentational State Transfer,中文直譯「表徵狀態轉移」,這是個很拗口的詞。個人建議是先不要強行理解,直接看怎麼作,等對實施細節有一些瞭解後,再來看名字會有更深入的理解。REST 是一套風格約定,RESTful 是它的形容詞形式;好比一套實現了 REST 風格的接口,能夠稱之爲 RESTful 接口。api
REST 用來規範應用如何在 HTTP 層與 API 提供方進行數據交互;在現階段,你應該已經很熟悉 GET 和 POST 請求;甚至有可能由於受限於後端框架限制等緣由,你的整個應用全都是用這兩種 HTTP 方法來完成的。這樣無疑浪費了 HTTP 協議的潛力,而 REST 則充分利用了 HTTP 規範中的方法,達到接口描述的語義化。安全
REST 描述了 HTTP 層裏客戶端和服務器端的數據交互規則;客戶端經過向服務器端發送 HTTP(s)請求,接收服務器的響應,完成一次 HTTP 交互。這個交互過程當中,REST 架構約定兩個重要方面就是 HTTP 請求的所採用方法,以及請求的連接。服務器
在請求層面,REST 規範能夠簡單粗暴抽象成如下兩個規則:restful
1. 請求 API 的 URL 表示用來定位資源;網絡
2. 請求的 METHOD 表示對這個資源進行的操做;架構
如下將以這兩個規則爲基礎,描述如何構造一個符合 REST 規範的請求。
1、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 架構的連接應該是這個樣子:
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 的成員)
2、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 請求操做後的內容是:
{ "id": 123, "name": "PUT Update" }
能夠觀察到,資源原有的 age 字段被清除掉了。
而若是改用 PATCH 的話,
PATCH /api/users/123 { "name": "PATCH Update" }
更新後的內容是:
{ "id": 123, "name": "PATCH Update", "age": 20 }
請求中指定的 name 屬性被更新了,而原有的 age 屬性則保持不變。
PATCH 的做用在於若是一個資源有不少字段,在進行局部更新時,只須要傳入須要修改的字段便可。不然在用 PUT 的狀況下,你不得不將整個資源模型全都發送回服務器,形成網絡資源的極大浪費。
【Delete】,資源的刪除,相應的請求 HTTP 方法就是 DELETE。這個也應當被實現爲一個冪等的方法。如:
DELETE /api/users/123
用於刪除服務器上 ID 爲 123 的資源,屢次請求產生反作用都是,是服務器上 ID 爲 123 的資源不存在。
3、分頁、過濾
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 的更多詳細規範,能夠參考這個倉庫。