在了解 REST API URI 設(shè)計(jì)的規(guī)則之前,讓我們快速過一下我們將要討論的一些術(shù)語(yǔ)。
URI
REST API 使用統(tǒng)一資源標(biāo)識(shí)符(URI)來尋址資源。在今天的網(wǎng)站上,URI 設(shè)計(jì)范圍從可以清楚地傳達(dá)API的資源模型,如:
http://api.example.com/louvre/leonardo-da-vinci/mona-lisa
到那些難以讓人理解的,比如:
http://api.example.com/68dd0-a9d3-11e0-9f1c-0800200c9a66
Tim Berners-Lee 在他的“Web架構(gòu)公理”列表中列出了關(guān)于 URI 的不透明度的注釋:
唯一可以使用標(biāo)識(shí)符的是對(duì)對(duì)象的引用。當(dāng)你沒有取消引用時(shí),你不應(yīng)該查看 URI 字符串的內(nèi)容以獲取其他信息。
- Tim Berners-Lee
客戶端必須遵循 Web 的鏈接范例,將 URI 視為不透明標(biāo)識(shí)符。
REST API 設(shè)計(jì)人員應(yīng)該創(chuàng)建 URI,將 REST API 的資源模型傳達(dá)給潛在的客戶端開發(fā)人員。 在這篇文章中,我將嘗試為 REST API URsI 引入一套設(shè)計(jì)規(guī)則。
在深入了解規(guī)則之前,先看一下在 RFC 3986 中定義的通用 URI 語(yǔ)法,如下所示:
URI = scheme "://" authority "/" path ["?" query] ["#" fragment]
規(guī)則#1:URI中不應(yīng)包含尾隨的斜杠(/)
這是作為 URI 路徑中最后一個(gè)字符的最重要的規(guī)則之一,正斜杠(/)不會(huì)增加語(yǔ)義值,并可能導(dǎo)致混淆。 REST API 不應(yīng)該期望有一個(gè)尾部的斜杠,并且不應(yīng)該將它們包含在它們提供給客戶端的鏈接中。
許多 Web 組件和框架將平等對(duì)待以下兩個(gè) URI:
然而,URI 中的每個(gè)字符都會(huì)被計(jì)入作為資源的唯一標(biāo)識(shí)。
兩個(gè)不同的 URI 映射到兩個(gè)不同的資源。如果 URI 不同,那么資源也會(huì)不同,反之亦然。因此,REST API 必須生成和傳達(dá)清晰的 URI,并且不應(yīng)容忍任何客戶端嘗試去對(duì)一個(gè)資源進(jìn)行模糊的標(biāo)識(shí)。
更多的API可能會(huì)將客戶端重定向到末尾沒有斜杠的 URI 上,(他們也可能會(huì)返回 301 - 用于重新定位資源的 “Moved Permanently”)。
規(guī)則#2:正斜杠分隔符(/)必須用于指示層次關(guān)系
在 URI 的路徑部分的正斜杠(/),用于表示資源之間的層次關(guān)系。
例如:
http://api.canvas.com/shapes/polygons/quadrilaterals/squares
規(guī)則#3:應(yīng)使用連字符( - )來提高 URI 的可讀性
為了使你的 URI 容易被人檢索和解釋,請(qǐng)使用連字符( - )來提高長(zhǎng)路徑段中名稱的可讀性。在任何你將使用英文的空格或連字號(hào)的地方,在URI中都應(yīng)該使用連字符來替換。
例如:
http://api.example.com/blogs/guy-levin/posts/this-is-my-first-post
規(guī)則#4:不得在 URI 中使用下劃線(_)
文本查看器(如瀏覽器,編輯器等)經(jīng)常在 URI 下加下劃線,以提供可點(diǎn)擊的視覺提示。 根據(jù)應(yīng)用程序的字體,下劃線(_)字符可能被這個(gè)下劃線部分地遮蔽或完全隱藏。
為避免這種混淆,請(qǐng)使用連字符( - )而不是下劃線
規(guī)則#5:URI 路徑中首選小寫字母
方便的話,URI 路徑中首選小寫字母,因?yàn)榇髮懽帜赣袝r(shí)會(huì)導(dǎo)致問題。 RFC 3986 中將 URI 定義為區(qū)分大小寫,但協(xié)議頭和域名除外。
例如:
http://api.example.com/my-folder/my-doc
HTTP://API.EXAMPLE.COM/my-folder/my-doc
在 URI 格式規(guī)范(RFC 3986)中這兩個(gè) URI 是相同的。
http://api.example.com/My-Folder/my-doc
而這個(gè) URI 與上面的兩個(gè)卻是不同的。
規(guī)則#6:文件擴(kuò)展名不應(yīng)包含在 URI 中
在 Web 上,字符(.)通常用于分隔 URI 的文件名和擴(kuò)展名。
一個(gè) REST API 不應(yīng)在 URI 中包含人造的文件擴(kuò)展名,來表示消息實(shí)體的格式。 相反,他們應(yīng)該通過 header 頭中 Content-Type 屬性的媒體類型來確定如何處理實(shí)體的內(nèi)容。
http://api.college.com/students/3248234/courses/2005/fall.json
http://api.college.com/students/3248234/courses/2005/fall
不應(yīng)使用文件擴(kuò)展名來表示格式偏好。
應(yīng)鼓勵(lì) REST API 客戶端使用 HTTP 提供的格式選擇機(jī)制,即請(qǐng)求 header 中的 Accept 屬性。
為了實(shí)現(xiàn)簡(jiǎn)單的鏈接和調(diào)試的便捷,REST API 也可以通過查詢參數(shù)來支持媒體類型的選擇。
規(guī)則#7:端點(diǎn)名稱是單數(shù)還是復(fù)數(shù)?
這里采用保持簡(jiǎn)單的原則。雖然你的語(yǔ)法常識(shí)會(huì)告訴你使用復(fù)數(shù)來描述資源的單個(gè)實(shí)例是錯(cuò)誤的,但實(shí)際的答案是保持 URI 格式一致并且始終使用復(fù)數(shù)形式。
不必處理奇怪的復(fù)數(shù)(person/people, goose/geese),這使 API 消費(fèi)者的生活更美好,也使 API 提供商更容易實(shí)現(xiàn)(因?yàn)榇蠖鄶?shù)現(xiàn)代框架將在一個(gè)通用的 controller 中處理 /students 和 /students/3248234)。
但是你怎么處理關(guān)系呢?如果一個(gè)關(guān)系只能存在于另一個(gè)資源中,RESTful 原則可以提供有用的指導(dǎo)。我們來看一下這個(gè)例子。某個(gè)學(xué)生有一些課程。這些課程在邏輯上映射到端點(diǎn) /students,如下所示:
http://api.college.com/students/3248234/courses - 檢索該學(xué)生所學(xué)習(xí)的所有課程清單,學(xué)生編號(hào)為3248234。
http://api.college.com/students/3248234/courses/physics - 檢索該學(xué)生的物理課程,學(xué)生編號(hào)為3248234。
結(jié)論
當(dāng)你設(shè)計(jì) REST API 服務(wù)時(shí),你必須注意資源,這些資源由 URI 定義。
你正在構(gòu)建的服務(wù)中的每個(gè)資源,都將至少有一個(gè) URI 來標(biāo)識(shí)它。這個(gè) URI 最好是有意義的,并能充分描述資源。URI 應(yīng)遵循可預(yù)測(cè)的層次結(jié)構(gòu),以增強(qiáng)可理解性,從而提高可用性:可預(yù)測(cè)的意義在于它們是一致的,層次結(jié)構(gòu)建立在數(shù)據(jù)具有結(jié)構(gòu)關(guān)系的意義上。
RESTful API 是為消費(fèi)者編寫的。URI 的名稱和結(jié)構(gòu)應(yīng)該向消費(fèi)者傳達(dá)意義。通過遵循上述規(guī)則,你將創(chuàng)建一個(gè)更加清晰的 REST API。 這不是一個(gè) REST 規(guī)則或約束,而是增強(qiáng)了 API。
也建議你來看看這篇文章,http://blog.restcase.com/5-basic-rest-api-design-guidelines
為你的客戶設(shè)計(jì),而不是為你的數(shù)據(jù)。