REST 簡介
大佬繞路,小白多篇文章整合總結(jié)篇
REST 是一個(gè)術(shù)語的縮寫词疼,REpresentational State Transfer,中文直譯「表征狀態(tài)轉(zhuǎn)移」蝶涩。這只是一個(gè)名字而已不必強(qiáng)行解釋概念,關(guān)鍵是這個(gè)東西它干了什么窜司,直接看怎么做,根據(jù)大佬講有了一定項(xiàng)目經(jīng)驗(yàn)再來看名字會有更深刻的理解惠桃。REST 是一套風(fēng)格約定,RESTful 是它的形容詞形式辖试;比如一套實(shí)現(xiàn)了 REST 風(fēng)格的接口辜王,可以稱之為 RESTful 接口。
REST 對請求的約定
REST 用來規(guī)范應(yīng)用如何在 HTTP 層與 API 提供方進(jìn)行數(shù)據(jù)交互罐孝;在現(xiàn)階段呐馆,在對于學(xué)過JavaWeb的時(shí)候來說是基本寫過使用servlet的管理系統(tǒng),因此你應(yīng)該已經(jīng)很熟悉 GET 和 POST 請求;甚至有可能因?yàn)槭芟抻诤蠖丝蚣芟拗频仍蛏龅担愕恼麄€(gè)應(yīng)用全都是用這兩種 HTTP 方法來完成的摹恰。這樣無疑浪費(fèi)了 HTTP 協(xié)議的潛力,而 REST 則充分利用了 HTTP 規(guī)范中的方法怒见,達(dá)到接口描述的語義化俗慈。
REST 描述了 HTTP 層里客戶端和服務(wù)器端的數(shù)據(jù)交互規(guī)則;客戶端通過向服務(wù)器端發(fā)送 HTTP(s)請求遣耍,接收服務(wù)器的響應(yīng)闺阱,完成一次 HTTP 交互。這個(gè)交互過程中舵变,REST 架構(gòu)約定兩個(gè)重要方面就是 HTTP 請求的所采用方法酣溃,以及請求的鏈接瘦穆。
在請求層面,REST 規(guī)范可以簡單粗暴抽象成以下兩個(gè)規(guī)則:
\1. 請求 API 的 URL 表示用來定位資源赊豌;
\2. 請求的 METHOD 表示對這個(gè)資源進(jìn)行的操作扛或;
以下將以這兩個(gè)規(guī)則為基礎(chǔ),描述如何構(gòu)造一個(gè)符合 REST 規(guī)范的請求碘饼。
一熙兔、API 的 URL
URL 用來定位資源,跟要進(jìn)行的操作區(qū)分開艾恼,這就意味這 URL 不該有任何動詞住涉;
下面示例中的 get、create钠绍、search 等動詞舆声,都不應(yīng)該出現(xiàn)在 REST 架構(gòu)的后端接口路徑中。在以前柳爽,這些接口中的動名詞通常對應(yīng)后臺的某個(gè)函數(shù)媳握。比如:
/api/getUser
/api/createApp
/api/searchResult
/api/deleteAllUsers
當(dāng)我們需要對單個(gè)用戶進(jìn)行操作時(shí),根據(jù)操作的方式不同可能需要下面的這些接口:
/api/getUser (用來獲取某個(gè)用戶的信息磷脯,還需要以參數(shù)方式傳入用戶 id 信息)
/api/updateUser (用來更新用戶信息)
/api/deleteUser (用來刪除單個(gè)用戶)
/api/resetUser (重置用戶的信息)
更有甚者毙芜,可能在更新用戶不同信息時(shí),提供不同的接口争拐,比如:
/api/updateUserName
/api/updateUserEmail
/api/updateUser
這樣的弊端在于:首先加上了動詞,肯定是使 URL 更長了晦雨;其次對一個(gè)資源實(shí)體進(jìn)行不同的操作就是一個(gè)不同的 URL架曹,造成 URL 過多難以管理。
其實(shí)當(dāng)你回過頭看「URL」 這個(gè)術(shù)語的定義時(shí)闹瞧,更能理解這一點(diǎn)绑雄。URL 的意思是統(tǒng)一資源定位符,這個(gè)術(shù)語已經(jīng)清晰的表明奥邮,一個(gè) URL 應(yīng)該用來定位資源万牺,而不應(yīng)該摻入對操作行為的描述。
在 REST 架構(gòu)的鏈接應(yīng)該是這個(gè)樣子:
- URL 中不應(yīng)該出現(xiàn)任何表示操作的動詞洽腺,鏈接只用于對應(yīng)資源脚粟;
- URL 中應(yīng)該單復(fù)數(shù)區(qū)分,推薦的實(shí)踐是永遠(yuǎn)只用復(fù)數(shù)蘸朋;比如 GET /api/users 表示獲取用戶的列表核无;如果獲取單個(gè)資源,傳入 ID藕坯,比如 /api/users/123 表示獲取單個(gè)用戶的信息团南;
- 按照資源的邏輯層級噪沙,對 URL 進(jìn)行嵌套,比如一個(gè)用戶屬于某個(gè)團(tuán)隊(duì)吐根,而這個(gè)團(tuán)隊(duì)也是眾多團(tuán)隊(duì)之一正歼;那么獲取這個(gè)用戶的接口可能是這樣:
GET /api/teams/123/members/234 表示獲取 id 為 123 的小組下,id 為234 的成員信息
按照類似的規(guī)則拷橘,可以寫出如下的接口
/api/teams (對應(yīng)團(tuán)隊(duì)列表)
/api/teams/123 (對應(yīng) ID 為 123 的團(tuán)隊(duì))
/api/teams/123/members (對應(yīng) ID 為 123 的團(tuán)隊(duì)下的成員列表)
/api/teams/123/members/456 (對應(yīng) ID 為 123 的團(tuán)隊(duì)下 ID 未 456 的成員)
二局义、API 請求的方法
在很多系統(tǒng)中,幾乎只用 GET 和 POST 方法來完成了所有的接口操作膜楷;這個(gè)行為類似于全用 DIV 來布局旭咽。實(shí)際上,我們不只有GET 和 POST 可用赌厅,在 REST 架構(gòu)中穷绵,有以下幾個(gè)重要的請求方法:GET,POST特愿,PUT仲墨,PATCH,DELETE揍障。這幾個(gè)方法都可以與對數(shù)據(jù)的 CRUD 操作對應(yīng)起來目养。
【Read】,資源的讀取毒嫡,用 GET 請求癌蚁;比如:
GET /api/users ( 表示讀取用戶列表)
GET 應(yīng)當(dāng)實(shí)現(xiàn)為一個(gè)安全方法。用于獲取數(shù)據(jù)而不應(yīng)該產(chǎn)生副作用兜畸。
【Created】努释,資源的創(chuàng)建,用 POST 方法咬摇;
POST 是一個(gè)非冪等的方法伐蒂,多次調(diào)用會造成不同效果;
冪等(Idempotent):如果對服務(wù)器資源的多次請求與一次請求造成的副作用是一樣的的話肛鹏,那這個(gè)請求方法可以被認(rèn)為是冪等逸邦。
比如下面的請求會在服務(wù)器上創(chuàng)建一個(gè) name 屬性為 'John Snow' 的用戶;多次請求就會創(chuàng)建多個(gè)這樣的用戶在扰。
POST /api/users
{
"name": "John Snow"
}
【Update】缕减,資源的更新。用于更新的 HTTP 方法有兩個(gè)健田,PUT 和 PATCH烛卧。
他們都應(yīng)當(dāng)被實(shí)現(xiàn)為冪等方法,即多次同樣的更新請求應(yīng)當(dāng)對服務(wù)器產(chǎn)生同樣的副作用。
PUT 和 PATCH 有各自不同的使用場景:
PUT 用于更新資源的全部信息总放,在請求的 body 中需要傳入修改后的全部資源主體呈宇;
而 PATCH 用于局部更新,在 body 中只需要傳入需要改動的資源字段局雄。
設(shè)想服務(wù)器中有以下用戶資源 /api/users/123
{
"id": 123,
"name": "Original",
"age": 20
}
當(dāng)我們往后臺發(fā)送更新請求時(shí)甥啄,PATCH 和 PUT 造成的效果是不一樣。
PUT /api/users/123
{
"name": "PUT Update"
}
上述 PUT 請求操作后的內(nèi)容是:
{
"id": 123,
"name": "PUT Update"
}
可以觀察到炬搭,資源原有的 age 字段被清除掉了蜈漓。
而如果改用 PATCH 的話,
PATCH /api/users/123
{
"name": "PATCH Update"
}
更新后的內(nèi)容是:
{
"id": 123,
"name": "PATCH Update",
"age": 20
}
請求中指定的 name 屬性被更新了宫盔,而原有的 age 屬性則保持不變融虽。
PATCH 的作用在于如果一個(gè)資源有很多字段,在進(jìn)行局部更新時(shí)灼芭,只需要傳入需要修改的字段即可有额。否則在用 PUT 的情況下,你不得不將整個(gè)資源模型全都發(fā)送回服務(wù)器彼绷,造成網(wǎng)絡(luò)資源的極大浪費(fèi)巍佑。
【Delete】,資源的刪除寄悯,相應(yīng)的請求 HTTP 方法就是 DELETE萤衰。這個(gè)也應(yīng)當(dāng)被實(shí)現(xiàn)為一個(gè)冪等的方法。如:
DELETE /api/users/123
用于刪除服務(wù)器上 ID 為 123 的資源猜旬,多次請求產(chǎn)生副作用都是脆栋,是服務(wù)器上 ID 為 123 的資源不存在。
三洒擦、分頁筹吐、過濾
REST 風(fēng)格的接口地址,表示的可能是單個(gè)資源秘遏,也可能是資源的集合;當(dāng)我們需要訪問資源集合時(shí)嘉竟,設(shè)計(jì)良好的接口應(yīng)當(dāng)接受參數(shù)邦危,允許只返回滿足某些特定條件的資源列表。
比如支持以 offset 和 limit 參數(shù)來進(jìn)行分頁舍扰;
GET /api/users?offset=0&limit=20
支持提供關(guān)鍵詞進(jìn)行搜索倦蚪,以及排序
GET /api/users?keyword=john&sort=age
支持根據(jù)字段進(jìn)行過濾
GET /api/users?gender=male
設(shè)計(jì)合適的 API URL,以及選擇合適的請求方法边苹,可以語義化的描述一個(gè) HTTP 請求的操作陵且。
當(dāng)我們都熟悉且遵循這樣的規(guī)范后,基本可以看到一個(gè) REST 風(fēng)格的接口就知道如何使用這個(gè)接口進(jìn)行 CRUD 操作了。比如下面這面這個(gè)接口就表示搜索 ID 為 123 的圖書館的書慕购,并且書的信息里包含關(guān)鍵字「game」聊疲,返回前十條滿足條件的結(jié)果。
GET /api/libraries/123/books?keyword=game&sort=price&limit=10&offset=0
同樣沪悲,下面這個(gè)請求的意思也就很明顯了吧获洲。
PATCH /api/companies/123/employees/234
{
"salary": 2300
}
請求類型總結(jié)
GET(SELECT):從服務(wù)器取出資源(一項(xiàng)或多項(xiàng))。
POST(CREATE):在服務(wù)器新建一個(gè)資源殿如。
PUT(UPDATE):在服務(wù)器更新資源(客戶端提供改變后的完整資源)贡珊。
PATCH(UPDATE):在服務(wù)器更新資源(客戶端提供改變的屬性)。
DELETE(DELETE):從服務(wù)器刪除資源涉馁。
還有兩個(gè)不常用的請求
HEAD:獲取資源的元數(shù)據(jù)门岔。
OPTIONS:獲取信息,關(guān)于資源的哪些屬性是客戶端可以改變的烤送。