RESTful API設(shè)計(jì)

項(xiàng)目資源的URL應(yīng)該如何設(shè)計(jì)浪秘?用名詞復(fù)數(shù)還是用名詞單數(shù)漓帅?一個資源需要多少個URL?用哪種HTTP方法來創(chuàng)建一個新的資源炕泳?可選參數(shù)應(yīng)該放在哪里纵诞?那些不涉及資源操作的URL呢?實(shí)現(xiàn)分頁和版本控制的最好方法是什么培遵?因?yàn)橛刑嗟囊蓡栒丬剑O(shè)計(jì)RESTful API變得很棘手登刺。在這篇文章中,我們來看一下RESTful API設(shè)計(jì)嗡呼,并給出一個最佳實(shí)踐方案纸俭。

每個資源使用兩個URL

資源集合用一個URL,具體某個資源用一個URL:

/employees#資源集合的URL

/employees/56#具體某個資源的URL

用名詞代替動詞表示資源

這讓你的API更簡潔南窗,URL數(shù)目更少揍很。不要這么設(shè)計(jì):

/getAllEmployees ? /getAllExternalEmployees ? /createEmployee ? /updateEmployee

更好的設(shè)計(jì):

GET /employees ? GET /employees?state=external ? POST /employees ? PUT /employees/56

用HTTP方法操作資源

使用URL指定你要用的資源。使用HTTP方法來指定怎么處理這個資源万伤。使用四種HTTP方法POST窒悔,GET,PUT壕翩,DELETE可以提供CRUD功能(創(chuàng)建蛉迹,獲取,更新放妈,刪除)。

獲燃霾佟:使用GET方法獲取資源芜抒。GET請求從不改變資源的狀態(tài)。無副作用托启。GET方法是冪等的宅倒。GET方法具有只讀的含義。因此屯耸,你可以完美的使用緩存拐迁。

創(chuàng)建:使用POST創(chuàng)建新的資源。

更新:使用PUT更新現(xiàn)有資源疗绣。

刪除:使用DELETE刪除現(xiàn)有資源线召。

2個URL乘以4個HTTP方法就是一組很好的功能《喟看看這個表格:

POST(創(chuàng)建)GET(讀然貉汀)PUT(更新)DELETE(刪除)

/employees創(chuàng)建一個新員工列出所有員工批量更新員工信息刪除所有員工

/employees/56(錯誤)獲取56號員工的信息更新56號員工的信息刪除56號員工

對資源集合的URL使用POST方法,創(chuàng)建新資源

創(chuàng)建一個新資源的時塔逃,客戶端與服務(wù)器是怎么交互的呢讯壶?

在資源集合URL上使用POST來創(chuàng)建新的資源過程

1、客戶端向資源集合URL/employees發(fā)送POST請求湾盗。HTTP body 包含新資源的屬性 “Albert Stark”伏蚊。

2、RESTful Web服務(wù)器為新員工生成ID格粪,在其內(nèi)部模型中創(chuàng)建員工躏吊,并向客戶端發(fā)送響應(yīng)肺孵。這個響應(yīng)的HTTP頭部包含一個Location字段,指示創(chuàng)建資源可訪問的URL颜阐。

對具體資源的URL使用PUT方法平窘,來更新資源

使用PUT更新已有資源。

1凳怨、客戶端向具體資源的URL發(fā)送PUT請求/employee/21瑰艘。請求的HTTP body中包含要更新的屬性值(21號員工的新名稱“Bruce Wayne”)。

2肤舞、REST服務(wù)器更新ID為21的員工名稱紫新,并使用HTTP狀態(tài)碼200表示更改成功。

推薦用復(fù)數(shù)名詞

推薦:

/employees ? /employees/21

不推薦:

/employee ? /employee/21

事實(shí)上李剖,這是個人愛好問題芒率,但復(fù)數(shù)形式更為常見。此外篙顺,在資源集合URL上用GET方法偶芍,它更直觀,特別是GET /employees?state=external德玫、POST /employees匪蟀、PUT /employees/56。但最重要的是:避免復(fù)數(shù)和單數(shù)名詞混合使用宰僧,這顯得非巢谋耄混亂且容易出錯。

對可選的琴儿、復(fù)雜的參數(shù)段化,使用查詢字符串(?)造成。

不推薦做法:

GET /employees ? GET /externalEmployees ? GET /internalEmployees ? GET /internalAndSeniorEmployees

為了讓你的URL更小显熏、更簡潔。為資源設(shè)置一個基本URL谜疤,將可選的佃延、復(fù)雜的參數(shù)用查詢字符串表示。

GET /employees?state=internal&maturity=senior

使用HTTP狀態(tài)碼

RESTful Web服務(wù)應(yīng)使用合適的HTTP狀態(tài)碼來響應(yīng)客戶端請求

2xx - 成功 - 一切都很好

4xx - 客戶端錯誤 - 如果客戶端發(fā)生錯誤(例如客戶端發(fā)送無效請求或未被授權(quán))

5xx – 服務(wù)器錯誤 - 如果服務(wù)器發(fā)生錯誤(例如夷磕,嘗試處理請求時出錯) 參考維基百科上的HTTP狀態(tài)代碼履肃。但是,其中的大部分HTTP狀態(tài)碼都不會被用到坐桩,只會用其中的一小部分尺棋。通常會用到一下幾個:

2xx:成功3xx:重定向4xx:客戶端錯誤5xx:服務(wù)器錯誤

200 成功301 永久重定向400 錯誤請求500 內(nèi)部服務(wù)器錯誤

201 創(chuàng)建304 資源未修改401未授權(quán)

403 禁止

404 未找到

返回有用的錯誤提示

除了合適的狀態(tài)碼之外,還應(yīng)該在HTTP響應(yīng)正文中提供有用的錯誤提示和詳細(xì)的描述。這是一個例子膘螟。 請求:

GET /employees?state=super

響應(yīng):

// 400 Bad Request

{"message":"You submitted an invalid state. Valid state values are 'internal' or 'external'","errorCode":352,"additionalInformation":"http://www.domain.com/rest/errorcode/352"

}

使用小駝峰命名法

使用小駝峰命名法作為屬性標(biāo)識符成福。

{"yearOfBirth":1982}

不要使用下劃線(year_of_birth)或大駝峰命名法(YearOfBirth)。通常荆残,RESTful Web服務(wù)將被JavaScript編寫的客戶端使用奴艾。客戶端會將JSON響應(yīng)轉(zhuǎn)換為JavaScript對象(通過調(diào)用var person = JSON.parse(response))内斯,然后調(diào)用其屬性蕴潦。因此,最好遵循JavaScript代碼通用規(guī)范俘闯。

對比:

person.year_of_birth// 不推薦潭苞,違反JavaScript代碼通用規(guī)范

person.YearOfBirth// 不推薦,JavaScript構(gòu)造方法命名

person.yearOfBirth// 推薦

在URL中強(qiáng)制加入版本號

從始至終真朗,都使用版本號發(fā)布您的RESTful API此疹。將版本號放在URL中以是必需的。如果您有不兼容和破壞性的更改遮婶,版本號將讓你能更容易的發(fā)布API蝗碎。發(fā)布新API時,只需在增加版本號中的數(shù)字蹭睡。這樣的話衍菱,客戶端可以自如的遷移到新API,不會因調(diào)用完全不同的新API而陷入困境肩豁。

使用直觀的 “v” 前綴來表示后面的數(shù)字是版本號。

/v1/employees

你不需要使用次級版本號(“v1.2”)辫呻,因?yàn)槟悴粦?yīng)該頻繁的去發(fā)布API版本清钥。

提供分頁信息

一次性返回數(shù)據(jù)庫所有資源不是一個好主意。因此放闺,需要提供分頁機(jī)制祟昭。通常使用數(shù)據(jù)庫中眾所周知的參數(shù)offset和limit。

/employees?offset=30&limit=15#返回30 到 45的員工

如果客戶端沒有傳這些參數(shù)怖侦,則應(yīng)使用默認(rèn)值篡悟。通常默認(rèn)值是offset = 0和limit = 10。如果數(shù)據(jù)庫檢索很慢匾寝,應(yīng)當(dāng)減小limit值搬葬。

/employees#返回0 到 10的員工

此外,如果您使用分頁艳悔,客戶端需要知道資源總數(shù)急凰。例: 請求:

GET /employees

響應(yīng):

{"offset":0,"limit":10,"total":3465,"employees": [//...] ? }

非資源請求用動詞

有時API調(diào)用并不涉及資源(如計(jì)算,翻譯或轉(zhuǎn)換)猜年。例:

GET /translate?from=de_DE&to=en_US&text=Hallo ? GET /calculate?para2=23?2=432

在這種情況下抡锈,API響應(yīng)不會返回任何資源疾忍。而是執(zhí)行一個操作并將結(jié)果返回給客戶端。因此床三,您應(yīng)該在URL中使用動詞而不是名詞一罩,來清楚的區(qū)分資源請求和非資源請求。

考慮特定資源搜索和跨資源搜索

提供對特定資源的搜索很容易撇簿。只需使用相應(yīng)的資源集合URL聂渊,并將搜索字符串附加到查詢參數(shù)中即可。

GET /employees?query=Paul

如果要對所有資源提供全局搜索补疑,則需要用其他方法歧沪。前文提到,對于非資源請求URL莲组,使用動詞而不是名詞诊胞。因此,您的搜索網(wǎng)址可能如下所示:

GET /search?query=Paul//返回 employees, customers, suppliers 等等.l

在響應(yīng)參數(shù)中添加瀏覽其它API的鏈接

理想情況下锹杈,不會讓客戶端自己構(gòu)造使用REST API的URL撵孤。讓我們思考一個例子。 客戶端想要訪問員工的薪酬表竭望。為此邪码,他必須知道他可以通過在員工URL(例如/employees/21/salaryStatements)中附加字符串“salaryStatements”來訪問薪酬表。這個字符串連接很容易出錯咬清,且難以維護(hù)闭专。如果你更改了訪問薪水表的REST API的方式(例如變成了/employees/21/salary-statement

或/employees/21/paySlips),所有客戶端都將中斷旧烧。 更好的方案是在響應(yīng)參數(shù)中添加一個links字段影钉,讓客戶端可以自動變更。

請求:

GET /employees/

響應(yīng):

//...{"id":1,"name":"Paul","links": [ ? ?? ? ? ? {"rel":"salary","href":"/employees/1/salaryStatements"} ? ?? ? ?] ? ?? },//...

如果客戶端完全依靠links中的字段獲得薪資表掘剪,你更改了API平委,客戶端將始終獲得一個有效的URL(只要你更改了link字段,請求的URL會自動更改)夺谁,不會中斷廉赔。另一個好處是,你的API變得可以自我描述匾鸥,需要寫的文檔更少蜡塌。

在分頁時,您還可以添加獲取下一頁或上一頁的鏈接示例扫腺。只需提供適當(dāng)?shù)钠坪拖拗频逆溄邮纠?/p>

GET /employees?offset=20&limit=10

{"offset":20,"limit":10,"total":3465,"employees": [//...],"links": [ ? ?? ? {"rel":"nextPage","href":"/employees?offset=30&limit=10"}, ? ?? ? {"rel":"previousPage","href":"/employees?offset=10&limit=10"} ? ??] ? }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末岗照,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌攒至,老刑警劉巖厚者,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異迫吐,居然都是意外死亡库菲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門志膀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熙宇,“玉大人,你說我怎么就攤上這事溉浙√讨梗” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵戳稽,是天一觀的道長馆蠕。 經(jīng)常有香客問我,道長惊奇,這世上最難降的妖魔是什么互躬? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮颂郎,結(jié)果婚禮上吼渡,老公的妹妹穿的比我還像新娘。我一直安慰自己乓序,他們只是感情好寺酪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著替劈,像睡著了一般房维。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抬纸,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音耿戚,去河邊找鬼湿故。 笑死,一個胖子當(dāng)著我的面吹牛膜蛔,可吹牛的內(nèi)容都是我干的坛猪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼皂股,長吁一口氣:“原來是場噩夢啊……” “哼墅茉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤就斤,失蹤者是張志新(化名)和其女友劉穎悍募,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洋机,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坠宴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绷旗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喜鼓。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖衔肢,靈堂內(nèi)的尸體忽然破棺而出庄岖,到底是詐尸還是另有隱情,我是刑警寧澤角骤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布隅忿,位于F島的核電站,受9級特大地震影響启搂,放射性物質(zhì)發(fā)生泄漏硼控。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一胳赌、第九天 我趴在偏房一處隱蔽的房頂上張望牢撼。 院中可真熱鬧,春花似錦疑苫、人聲如沸熏版。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撼短。三九已至,卻和暖如春挺勿,著一層夾襖步出監(jiān)牢的瞬間曲横,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工不瓶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留禾嫉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓蚊丐,卻偏偏與公主長得像熙参,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子麦备,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容