一文梳理REST API的設(shè)計原則

什么是 REST ?

REST架構(gòu)風(fēng)格描述了六個約束阳似。應(yīng)用于體系結(jié)構(gòu)的這些約束最初由Roy Fielding在他的博士論文中提出(參見 https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)該文是RESTful-style的基礎(chǔ) 。

這六個約束是:


Uniform Interface (統(tǒng)一接口)

統(tǒng)一接口約束定義了客戶端和服務(wù)器之間的接口铐伴。它簡化并解耦了架構(gòu)撮奏,使每個部件都能獨(dú)立演變。 統(tǒng)一接口的四個指導(dǎo)原則是:


Resource-Based (基于資源的)

使用URI作為資源標(biāo)識符在請求中標(biāo)識各個資源当宴。 資源本身在概念上與返回給客戶端的表示(representations)分開畜吊。 例如,服務(wù)器不直接發(fā)送其數(shù)據(jù)庫內(nèi)容即供,而是發(fā)送一些表示某些數(shù)據(jù)庫記錄的HTML定拟,XML或JSON,例如逗嫡,用芬蘭語表示并以UTF-8編碼,具體取決于請求的詳細(xì)信息和服務(wù)器實(shí)現(xiàn)株依。


Manipulation of Resources Through Representations

當(dāng)客戶端持有資源的表示(包括附加的任何元數(shù)據(jù))時驱证,它有足夠的信息來修改或刪除服務(wù)器上的資源,前提是它有權(quán)這樣做恋腕。


Self-descriptive Messages (自描述信息)

每條消息都包含足夠的信息來描述如何處理該消息抹锄。 例如,要調(diào)用的解析器可以由Internet媒體類型 media type(以前稱為MIME類型)指定。 響應(yīng)還明確指出了它們是否可以被緩存伙单。


Hypermedia as the Engine of Application State (HATEOAS) (超媒體作為應(yīng)用程序狀態(tài)引擎)

客戶端通過body 內(nèi)容获高,查詢字符串參數(shù),請求header和請求的URI(資源名稱)來提供狀態(tài)吻育。 服務(wù)通過正文內(nèi)容念秧,響應(yīng)代碼和響應(yīng)標(biāo)頭向客戶提供狀態(tài)。 這在技術(shù)上被稱為超媒體(或超文本中的超鏈接)布疼。


除了上面的描述之外摊趾,HATEOS還意味著,在必要時游两,鏈接包含在返回的正文(或標(biāo)題)中砾层,以提供用于檢索對象本身或相關(guān)對象的URI。 我們稍后會詳細(xì)討論這個問題贱案。


任何REST服務(wù)必須提供的統(tǒng)一接口是其設(shè)計的基礎(chǔ)


Stateless (無狀態(tài)的)

由于REST是REpresentational State Transfer的首字母縮寫肛炮,statelessness (無狀態(tài))是關(guān)鍵。 這意味著要處理請求的狀態(tài)必須包含在請求本身中宝踪,無論是作為URI侨糟,查詢字符串參數(shù),正文還是標(biāo)題的一部分肴沫。 URI唯一標(biāo)識資源粟害,body包含該資源的狀態(tài)(或狀態(tài)變化)。 然后颤芬,在服務(wù)器進(jìn)行處理之后悲幅,通過headers,狀態(tài)和響應(yīng)主體將適當(dāng)?shù)臓顟B(tài)或重要狀態(tài)的片斷傳送回客戶端站蝠。


我們大多數(shù)已經(jīng)在業(yè)界工作了一段時間的人習(xí)慣于在container(不是docker中的) 內(nèi)編程汰具,這為我們提供了“session”的概念,它在多個HTTP請求中維護(hù)狀態(tài)菱魔。 在REST中留荔,客戶端必須包含服務(wù)器的所有信息以完成請求,如果該狀態(tài)必須跨越多個請求澜倦,則根據(jù)需要重新發(fā)送狀態(tài)聚蝶。 無狀態(tài)可以實(shí)現(xiàn)更高的可伸縮性,因?yàn)榉?wù)器不必維護(hù)藻治,更新或傳遞該會話狀態(tài)碘勉。 此外,負(fù)載均衡器不必?fù)?dān)心無狀態(tài)系統(tǒng)的會話親和性桩卵。


那么狀態(tài)(state)和資源(resource)之間的區(qū)別是什么验靡? 狀態(tài)或應(yīng)用程序狀態(tài)是服務(wù)器關(guān)心的倍宾,以滿足當(dāng)前會話或請求所需的請求數(shù)據(jù)。 資源或資源狀態(tài)是定義資源表示的數(shù)據(jù) - 例如胜嗓,存儲在數(shù)據(jù)庫中的數(shù)據(jù)高职。 將應(yīng)用程序狀態(tài)視為可能因客戶端和每個請求而異的數(shù)據(jù)。 另一方面辞州,資源狀態(tài)在請求它的每個客戶端都是不變的怔锌。


Cacheable

與萬維網(wǎng)一樣,客戶端可以緩存響應(yīng)孙技。 因此产禾,響應(yīng)必須隱式或顯式地將自身定義為可緩存或不可緩存,以防止客戶端重用陳舊或不適當(dāng)?shù)臄?shù)據(jù)以影響進(jìn)一步的請求牵啦。 管理良好的緩存部分或完全消除了一些客戶端 - 服務(wù)器交互亚情,進(jìn)一步提高了可伸縮性和性能。


Client-Server

統(tǒng)一接口將客戶端與服務(wù)器分開哈雏。 這種關(guān)注點(diǎn)分離意味著楞件,例如,客戶端不關(guān)心數(shù)據(jù)存儲裳瘪,數(shù)據(jù)存儲仍保留在每個服務(wù)器的內(nèi)部土浸,從而提高了客戶端代碼的可移植性。 服務(wù)器不關(guān)心用戶界面或用戶狀態(tài)彭羹,因此服務(wù)器可以更簡單黄伊,更具可伸縮性。 只要不改變接口派殷,服務(wù)器和客戶端也可以獨(dú)立替換和開發(fā)还最。


Layered System (分層系統(tǒng))

客戶端通常無法判斷它是直接連接到終端服務(wù)器,還是中間服務(wù)器毡惜。 中間服務(wù)器可以通過啟用負(fù)載平衡和提供共享緩存來提高系統(tǒng)可伸縮性拓轻。 Layers 也可以實(shí)施安全策略。


Code on Demand (optional)

服務(wù)器能夠通過向客戶端傳輸可以執(zhí)行的邏輯來臨時擴(kuò)展或自定義客戶端的功能经伙。 這樣的示例可以包括編譯的組件扶叉,例如Java applet和客戶端腳本,例如JavaScript帕膜。


遵守這些約束枣氧,從而符合REST架構(gòu)風(fēng)格,將使任何類型的分布式超媒體系統(tǒng)具有理想的緊急(emergent)屬性垮刹,例如性能作瞄,可伸縮性,簡單性危纫,可修改性,可見性,可移植性和可靠性种蝶。


注意:REST架構(gòu)的唯一可選約束是code on demand契耿。 如果服務(wù)違反任何其他約束,則嚴(yán)格來講不能將其稱為RESTful螃征。


REST API Quick Tips

無論技術(shù)上是不是REST(根據(jù)前面提到的六個約束條件)搪桂,這里有一些推薦的類似REST的概念。 這六個快速提示將帶來更好盯滚,更實(shí)用的服務(wù)踢械。


使用HTTP動詞使你的請求帶有含意

API使用者能夠發(fā)送GET,POST魄藕,PUT和DELETE請求内列,這極大地增強(qiáng)了給定請求的清晰度。


通常背率,四個主要的HTTP動詞使用如下:


GET :讀取特定資源(通過標(biāo)識符)或資源集合话瞧。


PUT :更新特定資源(通過標(biāo)識符)或資源集合。 如果資源標(biāo)識符是事先已知的寝姿,也可以用于創(chuàng)建特定資源交排。


DELETE :通過標(biāo)識符刪除指定資源。


POST :創(chuàng)建一個新資源饵筑。 對于不適合其他類別的操作埃篓,也是一個萬能的動詞。


注意 :GET請求不得更改任何底層資源數(shù)據(jù)根资。 但可能會更新測量和跟蹤數(shù)據(jù)架专,但URI標(biāo)識的資源數(shù)據(jù)不應(yīng)更改。


提供合理的資源名稱

制作出色的API需要80%的藝術(shù)和20%的科學(xué)嫂冻。 創(chuàng)建表示合理資源的URL層次結(jié)構(gòu)是藝術(shù)部分胶征。 擁有合理的資源名稱(只是URL路徑,例如/customers/12345/orders)可以提高給定請求的清晰度桨仿。


適當(dāng)?shù)馁Y源名稱為服務(wù)請求提供上下文睛低,從而提高API的可理解性。 通過URI名稱對資源進(jìn)行分層查看服傍,為消費(fèi)者提供友好钱雷,易于理解的資源層次結(jié)構(gòu),以便在其應(yīng)用程序中使用吹零。


以下是一些URL路徑(資源名稱)設(shè)計的規(guī)則:

在你的網(wǎng)址中使用標(biāo)識符罩抗,而不是在查詢字符串中使用。 使用URL查詢字符串參數(shù)非常適合過濾灿椅,但不適用于資源名稱套蒂。

Good: /users/12345

Poor: /api?type=user&id=23

利用URL的分層特性來表示結(jié)構(gòu)

為你的客戶而不是數(shù)據(jù)設(shè)計

資源名稱應(yīng)為名詞

避免使用動詞作為資源名稱钞支,以提高清晰度。 使用HTTP methods 指定請求的動詞部分操刀。

在URL段中使用復(fù)數(shù)形式烁挟,使用集合使API URI在所有HTTP方法中保持一致。

Recommended: /customers/33245/orders/8769/lineitems/1

Not: /customer/33245/order/8769/lineitem/1

避免在URL中使用集合詞

例如'customer_list'作為資源骨坑。 使用復(fù)數(shù)來隱含表示集合(例如撼嗓,customers 代替customer_list)。

在URL段中使用小寫欢唾,用下劃線('_')或連字符(' - ')分隔單詞

有些服務(wù)器會忽略大小寫且警,所以最好清楚。

保持URL盡可能短礁遣,盡可能少的分段


使用HTTP響應(yīng)代碼指示狀態(tài)

響應(yīng)狀態(tài)代碼是HTTP規(guī)范的一部分斑芜。 它們中有很多可以gggg解決最常見的情況。 本著使RESTful服務(wù)包含HTTP規(guī)范的精神亡脸,我們的Web API應(yīng)該返回相關(guān)的HTTP狀態(tài)代碼押搪。 例如,當(dāng)成功創(chuàng)建資源時(例如浅碾,來自POST請求)大州,API應(yīng)該返回HTTP狀態(tài)代碼201.這里有常用的HTTP狀態(tài)代碼列表,其列出了每個的詳細(xì)描述垂谢。


十大HTTP響應(yīng)狀態(tài)代碼的建議用法如下:


200 OK :通用成功狀態(tài)代碼厦画。 這是最常見的代碼。 用于表示成功滥朱。

201 CREATED :成功創(chuàng)建(通過POST或PUT)根暑。 將Location header設(shè)置為包含指向新創(chuàng)建的資源的鏈接(在POST上)。 響應(yīng)body 內(nèi)容可能存在也可能不存在徙邻。

204 NO CONTENT :表示成功排嫌,但響應(yīng)body中沒有任何內(nèi)容,通常用于DELETE和PUT操作缰犁。

400 BAD REQUEST :完成請求時的一般錯誤會導(dǎo)致無效狀態(tài)淳地。 例如域驗(yàn)證錯誤,缺少數(shù)據(jù)等帅容。

401 UNAUTHORIZED :丟失或無效的身份驗(yàn)證令牌颇象。

403 FORBIDDEN :當(dāng)用戶未被授權(quán)執(zhí)行操作或資源由于某種原因(例如時間限 制等)不可用時的錯誤代碼。

404 NOT FOUND :在找不到請求的資源時使用并徘,不管是否不存在遣钳,或者是否是401或403,出于安全原因麦乞,服務(wù)需要屏蔽。

405 METHOD NOT ALLOWED :表示請求的URL存在,但請求的HTTP方法不對。 例如,POST /users/12345选浑,其API不支持以這種方式創(chuàng)建資源(使用提供的ID)。 返回405時必須設(shè)置Allow header表明支持的HTTP方法浸锨。 例如:"Allow: GET, PUT, DELETE"

409 CONFLICT :請求導(dǎo)致資源沖突時榨咐。 重復(fù)條目,例如嘗試創(chuàng)建具有相同信息的兩個客戶砰识,以及在不支持級聯(lián)刪除時刪除根對象能扒。

500 INTERNAL SERVER ERROR :永遠(yuǎn)不要故意返回該狀態(tài)碼。 服務(wù)器端拋出異常時應(yīng)使用catch-all捕捉辫狼。 僅將此用于客戶端無法解決的錯誤(即服務(wù)器錯誤初斑,client做啥也沒有用,請聯(lián)系后端人員解決)膨处。


提供JSON和XML

一般只支持JSON就可以了见秤,除非是高度標(biāo)準(zhǔn)化和受監(jiān)管的行業(yè),需要XML真椿。 模式驗(yàn)證和命名空間鹃答,并提供JSON和XML,是非常高的突硝。 理想情況下测摔,讓消費(fèi)者使用HTTP Accept header在格式之間切換,或者只是在URL上將.xml的擴(kuò)展名更改為.json解恰。


請注意锋八,一旦我們開始討論XML支持,我們就會開始討論用于驗(yàn)證护盈,命名空間等的模式挟纱。除非你的行業(yè)需要,否則請盡量避免支持所有這些復(fù)雜性腐宋。 JSON旨在簡化紊服,簡潔和實(shí)用。 如果可以的話脏款,讓你的XML看起來更簡潔围苫。


換句話說,使返回的XML更像JSON - 簡單易讀撤师,不存在架構(gòu)和命名空間細(xì)節(jié)剂府,只有數(shù)據(jù)和鏈接。 如果它最終比這更復(fù)雜剃盾,那么XML的成本將是驚人的腺占。 根據(jù)我的經(jīng)驗(yàn)淤袜,過去幾年沒有人使用過XML響應(yīng),成本太昂貴了衰伯。


請注意铡羡,JSON-Schema提供了架構(gòu)式驗(yàn)證功能。


創(chuàng)建細(xì)粒度資源

在開始時意鲸,最好創(chuàng)建模仿系統(tǒng)的底層應(yīng)用程序域模型或數(shù)據(jù)庫體系結(jié)構(gòu)的API烦周。 最終,聚合那些需要利用多個底層資源的服務(wù)來減少通信量怎顾。 但是读慎,從單個資源創(chuàng)建更大的資源比從更大的聚合創(chuàng)建細(xì)粒度或單個資源要容易得多。 讓自己輕松自如槐雾,從易于定義的小型資源開始夭委,為這些資源提供CRUD功能。 你可以之后創(chuàng)建這些方面的用例募强,減少通信株灸。


考慮連接性

REST的原則之一是連通性 - 通過超媒體鏈接(搜索HATEOAS)。 雖然沒有超鏈接擎值,服務(wù)仍然有用慌烧,但在響應(yīng)中返回鏈接時,API會變得更具自我描述性和可發(fā)現(xiàn)性幅恋。 至少杏死,“自我描述”的鏈接引用會告訴客戶端如何檢索數(shù)據(jù)。 此外捆交,利用HTTP Location header 包含通過POST(或PUT)創(chuàng)建資源的鏈接淑翼。 對于在支持分頁的響應(yīng)中返回的集合,“first”品追,“l(fā)ast”玄括,“next”和“prev”鏈接至少是非常有用的。


關(guān)于鏈接格式肉瓦,有很多遭京。 HTTP Web鏈接規(guī)范(RFC5988)解釋了如下鏈接:


鏈接是由Internationalised Resource Identifiers (IRIs) [RFC3987]標(biāo)識的兩個資源之間的類型連接,包括:

上下文IRI泞莉,

鏈接關(guān)系類型

目標(biāo)IRI哪雕,和

可選的目標(biāo)屬性。

鏈接可以被視為“{context IRI}在{target IRI}具有{relation type}資源的形式的聲明鲫趁,其具有{target attributes}斯嚎。”


至少,按照規(guī)范中的建議放置HTTP鏈接頭中的鏈接堡僻,或者在JSON表示中包含此HTTP鏈接樣式的JSON表示(例如Atom樣式鏈接糠惫,請參閱:RFC4287)。 之后钉疫,隨著REST API變得更加成熟硼讽,你可以在更復(fù)雜的鏈接樣式中進(jìn)行分層,例如HAL + JSON牲阁,Siren固阁,Collection + JSON 或 JSON-LD等。

聲明:本文轉(zhuǎn)載自蛙課網(wǎng)官方網(wǎng)站

想獲取更多資訊咨油、更多視頻您炉、面試題答案,還有各種資源+源碼+工具

就關(guān)注“蛙課網(wǎng)幸鄣纾”公眾號吧!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棉胀,一起剝皮案震驚了整個濱河市法瑟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唁奢,老刑警劉巖霎挟,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異麻掸,居然都是意外死亡酥夭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門脊奋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熬北,“玉大人,你說我怎么就攤上這事诚隙⊙纫” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵久又,是天一觀的道長巫延。 經(jīng)常有香客問我,道長地消,這世上最難降的妖魔是什么炉峰? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮脉执,結(jié)果婚禮上疼阔,老公的妹妹穿的比我還像新娘。我一直安慰自己适瓦,他們只是感情好竿开,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布谱仪。 她就那樣靜靜地躺著,像睡著了一般否彩。 火紅的嫁衣襯著肌膚如雪疯攒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天列荔,我揣著相機(jī)與錄音敬尺,去河邊找鬼。 笑死贴浙,一個胖子當(dāng)著我的面吹牛砂吞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播崎溃,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蜻直,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了袁串?” 一聲冷哼從身側(cè)響起概而,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎囱修,沒想到半個月后赎瑰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡破镰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年餐曼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲜漩。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡源譬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宇整,到底是詐尸還是另有隱情瓶佳,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布鳞青,位于F島的核電站霸饲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏臂拓。R本人自食惡果不足惜厚脉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胶惰。 院中可真熱鬧傻工,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泄伪,卻和暖如春殴蓬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蟋滴。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工染厅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人津函。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓肖粮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尔苦。 傳聞我的和親對象是個殘疾皇子涩馆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359