<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          怎樣編寫好的API?看完你就知道了!

          共 7177字,需瀏覽 15分鐘

           ·

          2021-03-03 09:44

          作者 | Sebastian Buczyński
          譯者 | 張衛(wèi)濱
          策劃 | 萬(wàn)佳
          本文首先闡述了 RESTful 風(fēng)格 API 的基礎(chǔ)理論知識(shí)以及 Richardson 成熟度模型,隨后討論了好的 API 應(yīng)該具有哪些特征,最后對(duì)流行的 API 實(shí)現(xiàn)方式,即 GraphQL 和 RESTful,進(jìn)行了對(duì)比。

          現(xiàn)在,每個(gè)人都在關(guān)注 API。API 最早開始流行于大約 20 年前,2000 年,Roy Fielding 在他的博士論文中首次提出了 REST 這個(gè)術(shù)語(yǔ)。同年,Amazon、Salesforce 和 eBay 向全世界的開發(fā)者介紹了他們的 API,永遠(yuǎn)改變了我們構(gòu)建軟件的方式。

          在 REST 之前,Roy Fielding 論文中的原則被稱為“HTTP 對(duì)象模型”,隨后你會(huì)明白這為何非常重要。

          隨著閱讀的深入,你還會(huì)看到如何確定你的 API 是否成熟,好 API 的主要品質(zhì)是什么以及為何在構(gòu)建 API 的時(shí)候,要注重適應(yīng)性。

          1RESTful 架構(gòu)基礎(chǔ)

          REST 代表表述性狀態(tài)轉(zhuǎn)移(Representational State Transfer),由 Roy Fielding 在他的博士論文中定義,長(zhǎng)期以來(lái),它就是服務(wù) API 的圣杯。它并不是構(gòu)建 API 的唯一方式,但是由于它的流行,即便是非開發(fā)人員也知道這種標(biāo)準(zhǔn)。

          RESTful 軟件有如下六種特點(diǎn):

          • 客戶端 - 服務(wù)器端架構(gòu)

          • 無(wú)狀態(tài)

          • 可緩存

          • 分層系統(tǒng)

          • 按需編碼(可選)

          • 統(tǒng)一接口

          但是,對(duì)日常使用來(lái)說(shuō),這過(guò)于理論化了。我們需要更具操作性的東西,這也就是 API 成熟度模型。

          2Richardson 成熟度模型

          該模型是由 Leonard Richardson 提出的,它將 RESTful 開發(fā)原則結(jié)合成四個(gè)簡(jiǎn)單易行的步驟。


          在模型中的位置越高,就越接近 Roy Fielding 所定義的 RESTful 原始理念。

           Level 0:POX(Plain Old XML)的泥沼

          Level 0 的 API 是一組簡(jiǎn)單 XML 或 JSON 的描述。在前文中,我曾經(jīng)說(shuō)過(guò)在 Fielding 的論文之前,RESTful 原則被稱為“HTTP 對(duì)象模型”。

          這是因?yàn)?HTTP 是 RESTful 開發(fā)中最重要的組成部分。REST 要盡可能多地使用 HTTP 固有屬性中的理念。

          在 Level 0,沒有使用任何這樣的東西。我們只是構(gòu)建自己的協(xié)議并把它作為一個(gè)專有層。這種架構(gòu)被稱為遠(yuǎn)程過(guò)程調(diào)用(Remote Procedure Call,RPC),適用于遠(yuǎn)程過(guò)程 / 命令。

          通常我們會(huì)有一個(gè)端點(diǎn),可以對(duì)它進(jìn)行調(diào)用以獲取一堆 XML。在這方面,一個(gè)典型的例子就是 SOAP 協(xié)議:


          另外一個(gè)很好的例子就是 Slack API。它有些多樣化,有多個(gè)端點(diǎn),但依然是 RPC 風(fēng)格的 API。它暴露了 Slack 的各種功能,中間沒有附加任何特性。如下的代碼展示了如何向一個(gè)特定的通道發(fā)送消息:


          雖然按照 Richardson 的模型,這是一個(gè) Level 0 的 API,但是這并不意味著它是不好的。只要它是可用的,并且恰當(dāng)?shù)胤?wù)于業(yè)務(wù)需求,那它就是很棒的 API。

           Level 1:資源

          為了構(gòu)建 Level 1 的 API,我們需要找出系統(tǒng)中的名詞并將它們通過(guò)不同的 URL 暴露出來(lái),如下面的樣例所示:


          其中,“/api/books”能讓我訪問(wèn)一個(gè)通用的圖書目錄,“/api/profile”能夠讓我訪問(wèn)這些書的作者的基本信息。為了獲取某個(gè)資源的第一個(gè)特定實(shí)例,我可以在 URL 中添加 ID(或其他引用)。

          在 URL 中還可以嵌套資源,這展示了它們是以層級(jí)結(jié)構(gòu)的形式組織的。

          回到 Slack 的樣例,如下展示了按照 Level 1 API,它們會(huì)是什么樣子的:


          現(xiàn)在,URL 發(fā)生了變化,從原先的“/api/chat.postMessage”變成了現(xiàn)在的“/api/channels/general/messages”。

          信息中“channel”部分從請(qǐng)求體轉(zhuǎn)移到了 URL 中。從字面就能看出,通過(guò)使用這個(gè) URL,我們可以預(yù)期有條消息發(fā)布到了 general 通道上。

           Level 2:HTTP 動(dòng)作

          Level 2 利用 HTTP 動(dòng)作(verb)來(lái)添加更多的含義和意圖。在這方面可用的動(dòng)作比較多,我這里只用到一個(gè)基礎(chǔ)的子集:PUT / DELETE / GET / POST。

          借助這些動(dòng)作,我們可以預(yù)期包含它們的 URL 有不同的行為:

          • POST:創(chuàng)建新數(shù)據(jù)

          • PUT:更新現(xiàn)有的數(shù)據(jù)

          • DELETE:移除數(shù)據(jù)

          • GET:查找特定 id 的數(shù)據(jù)輸出,獲取某個(gè)資源(或整個(gè)集合)

          以上面提到的“/api/books”為例:


          那這里的“安全”和“冪等”又是什么意思呢?

          “安全”的方法指的是永遠(yuǎn)不會(huì)改變數(shù)據(jù)的方法。REST 建議 GET 方法只能用來(lái)獲取數(shù)據(jù),所以在上面的集合中,它是唯一一個(gè)安全的方法。不管你調(diào)用多少次基于 REST 的 GET 方法,它永遠(yuǎn)不會(huì)改變數(shù)據(jù)庫(kù)中的任何東西。但是,這并不是該動(dòng)作的固有特性,而是關(guān)系到你該如何實(shí)現(xiàn)它,所以我們需要確保它是這樣運(yùn)行的。所有其他的方法都會(huì)以不同的方式改變數(shù)據(jù),不能隨意使用。在 REST 中,GET 方法既是安全的,又是冪等的。

          “冪等”的方法指的是多次使用不會(huì)產(chǎn)生不同結(jié)果的方法。按照 REST,DELETE 方法應(yīng)該是冪等的,如果刪除了某個(gè)資源,然后針對(duì)相同的資源再次調(diào)用 DELETE,它不會(huì)改變?nèi)魏螙|西。資源應(yīng)該早就已經(jīng)消失了。在 REST 規(guī)范中,POST 是唯一一個(gè)非冪等的方法,所以我們可以對(duì)相同的資源多次調(diào)用 POST 方法,這樣我們會(huì)得到重復(fù)的資源。

          我們重新看一下 Slack 樣例,如果我們使用 HTTP 動(dòng)作來(lái)進(jìn)行更多的操作會(huì)是什么樣子:


          我們可以使用 POST 方法發(fā)送消息到通用的通道,我們也可以使用 GET 方法從通用通道獲取消息。我們還可以使用 DELETE 方法和特定的 ID 刪除消息,這里比較有意思的一點(diǎn)在于,消息并不是與特定通道關(guān)聯(lián)的,所以我可以設(shè)計(jì)一個(gè)單獨(dú)的 API 來(lái)刪除資源。這個(gè)例子表明,設(shè)計(jì) API 并不總是那么簡(jiǎn)單,這方面有很多可選項(xiàng)和權(quán)衡。

           Level 3:HATEOAS

          還記得純文字、沒有任何圖像的電腦游戲嗎?我們只能看到一些文本,描述了你在哪里,以及接下來(lái)能干什么。為了取得進(jìn)展,我們必須要輸入自己的選擇。在一定程度上來(lái)講,HATEOAS 就是做這件事情的。


          HATEOAS 指的是“超媒體作為應(yīng)用狀態(tài)引擎(Hypermedia as the Engine of Application State)”。

          有了 HATEOAS 之后,當(dāng)其他人使用你的 API 的時(shí)候,他們就能看到通過(guò) API 還能做哪些其他的事情。HATEOAS 回答了“從這里出發(fā),我還能去哪里?”的問(wèn)題。


          但這還不是所有的內(nèi)容。HATEOAS 還可以對(duì)數(shù)據(jù)關(guān)系進(jìn)行建模。我們可能會(huì)有一個(gè)關(guān)于圖書的資源,并且在 URL 中沒有將作者信息嵌套進(jìn)來(lái),但是我們可以包含它們的鏈接,如果有人對(duì)作者感興趣的話,那么他們可以訪問(wèn)這些鏈接并探索相關(guān)的數(shù)據(jù)。

          HATEOAS 不像其他成熟度模型的等級(jí)那樣流行,但是有些開發(fā)人員確實(shí)在使用它。其中一個(gè)樣例就是 Jira,如下是它們的搜索 API 的響應(yīng):


          他們將鏈接嵌入到了其他我們可以探索的資源中,以及該 issue 的狀態(tài)過(guò)渡列表。

          另外一個(gè)使用 HATEOAS 的樣例是 Artsy。他們的 API 嚴(yán)重依賴 HATEOAS,并且還使用了 JSON Plus 調(diào)用規(guī)范,按照該規(guī)范強(qiáng)制要求使用一種特殊的約定來(lái)構(gòu)建鏈接。下面是一個(gè)分頁(yè)的例子,這是使用 HATEOAS 最酷的樣例之一:


          我們可以提供到下一頁(yè)、上一頁(yè)、第一頁(yè)和最后一頁(yè)的鏈接,還可以按照需要添加其他頁(yè)面的鏈接。這樣簡(jiǎn)化了 API 的消費(fèi),因?yàn)檫@樣不需要在客戶端添加 URL 的解析邏輯,也不需要追加頁(yè)碼的方法。我們只需要在客戶端使用已經(jīng)實(shí)現(xiàn)結(jié)構(gòu)化的鏈接就可以了。

          3好的 API 由什么組成

          我們已經(jīng)介紹完了 Richardson 模型,但這并不是實(shí)現(xiàn)好的 API 的全部?jī)?nèi)容。其他重要的品質(zhì)還有什么呢?

           錯(cuò)誤 / 異常處理

          我對(duì)自己使用的 API 的基本期望之一就是,需要有一種明確的方式來(lái)判斷是否有錯(cuò)誤或異常。我想要知道請(qǐng)求是否得到了處理。

          HTTP 有一種簡(jiǎn)單的方式來(lái)實(shí)現(xiàn)這一點(diǎn):HTTP 狀態(tài)碼。

          管理狀態(tài)碼的基本規(guī)則是:

          • 2xx 代表一切正常

          • 3xx 代表你想要找的公主在另外一個(gè)城堡,也就是你要找的資源在其他的地方

          • 4xx 代表客戶端做錯(cuò)了某些事情

          • 5xx 代表服務(wù)器端失敗


          我們的 API 至少要提供 4xx 和 5xx 狀態(tài)碼。有時(shí)候,5xx 是自動(dòng)生成的。例如,客戶端發(fā)送了一些內(nèi)容到服務(wù)器端,但是這非法的請(qǐng)求,而我們的校驗(yàn)是有缺陷的,從而導(dǎo)致這個(gè)問(wèn)題繼續(xù)在代碼中執(zhí)行了下去,最終導(dǎo)致出現(xiàn)了異常,這樣就會(huì)返回一個(gè) 5xx 的狀態(tài)碼。

          如果你想要承諾使用特定的狀態(tài)碼,那么你會(huì)遇到“哪種狀態(tài)碼最適合當(dāng)前情況?”的問(wèn)題。這樣的問(wèn)題并不總是那么容易回答,我推薦你去閱讀聲明這些狀態(tài)碼的 RFC,它們給出了比其他來(lái)源更廣泛的解釋,并且告訴了你何時(shí)使用這些狀態(tài)碼更合適等。幸運(yùn)的是,網(wǎng)上有些資源可以幫助我們做出選擇,比如 Mozilla 的 HTTP 狀態(tài)碼指南。

          https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

           文檔

          優(yōu)秀的 API 必須要有優(yōu)秀的文檔。在文檔方面,最大的問(wèn)題在于,隨著 API 的發(fā)展需要找人同步更新文檔。有個(gè)更好的方案是不脫離代碼自更新文檔。

          例如,注釋與代碼的脫節(jié)。當(dāng)代碼發(fā)生變化的時(shí)候,注釋依然保持不變,這樣的話,注釋就過(guò)時(shí)了。這甚至?xí)雀揪蜎]有任何注釋更糟糕,因?yàn)樵陔S后的一段時(shí)間內(nèi),它們會(huì)提供錯(cuò)誤的信息。注釋不會(huì)自動(dòng)更新,所以開發(fā)人員需要記得在維護(hù)代碼的時(shí)候同時(shí)維護(hù)它們。

          自更新的文檔工具可以解決這個(gè)問(wèn)題。在這方面,一個(gè)流行的工具就是 Swagger,它是基于 OpenAPI 構(gòu)建的工具,可以很容易地描述你的 API。


          Swagger 很酷的一點(diǎn)在于它是可執(zhí)行的,所以如果你嘗試修改 API,能立即看到它的作用和變化。

          為了給 Swagger 添加自動(dòng)更新功能,我們需要使用其他的插件和工具。在 Python 中,有針對(duì)大多數(shù)主流框架的插件。它們能生成 API 請(qǐng)求該如何組織的描述,并定義數(shù)據(jù)的輸入和輸出。

          如果你不想要使用 Swagger,而是想使用更簡(jiǎn)單的工具,那該怎么辦呢?有個(gè)流行的替代方案是 Slate。

          https://slatedocs.github.io/slate/#introduction


          還有一些值得推薦的中間方案,如 widdershins 和 api2html 的組合,它允許我們從 Swagger 的定義中生成類似 Slate 的文檔。

          https://github.com/Mermade/widdershins

          https://api2html.com/docs/overview/

           緩存

          在有些系統(tǒng)中,緩存可能并不是什么大問(wèn)題。這樣的系統(tǒng)可能沒有很多的數(shù)據(jù)可供緩存,所有的數(shù)據(jù)都在不斷地發(fā)生變化,或者系統(tǒng)根本沒有很大的流量。

          但是,在大多數(shù)情況下,緩存對(duì)于良好的性能至關(guān)重要。它與 RESTful API 密切相關(guān),因?yàn)?HTTP 協(xié)議在緩存方面做了很多事情,比如 HTTP 頭信息允許我們控制緩存的行為。

          你可能想要在客戶端緩存東西,或者如果有注冊(cè)表或值存儲(chǔ)的話,那么你可能想要在應(yīng)用程序中緩存數(shù)據(jù)。但是,HTTP 讓我們能夠基本上免費(fèi)就可以獲得一個(gè)很好的緩存,所以如果可能的話,請(qǐng)不要錯(cuò)過(guò)這個(gè)免費(fèi)的午餐。


          同時(shí),因?yàn)榫彺媸?HTTP 規(guī)范的一部分,所以很多涉及 HTTP 的技術(shù)都知道如何進(jìn)行緩存:瀏覽器原生支持緩存,客戶端和服務(wù)器之間的中間技術(shù)也是如此。

          4API 設(shè)計(jì)的演化

          構(gòu)建 API 以及現(xiàn)代軟件最重要的部分就是適應(yīng)性。如果沒有適應(yīng)性,開發(fā)就會(huì)變慢,在合理的時(shí)間發(fā)布特性就會(huì)變得更加困難,當(dāng)面對(duì)最后截止時(shí)間的時(shí)候更是如此。

          “軟件架構(gòu)”在不同的上下文語(yǔ)境中有不同的含義,不過(guò)我們現(xiàn)在采用這個(gè)定義:

          軟件架構(gòu)一種行為 / 藝術(shù),能夠避免會(huì)阻礙未來(lái)變化的決策。

          記住了這一點(diǎn),在設(shè)計(jì)軟件的時(shí)候,當(dāng)你必須要在具有相似優(yōu)點(diǎn)的方案中做出選擇時(shí),你應(yīng)該始終選擇更多考慮到未來(lái)的方案。

          好的實(shí)踐并不是萬(wàn)能的。按照正確的方式構(gòu)建錯(cuò)誤的東西并不是你想要的結(jié)果。最好采取一種成長(zhǎng)的心態(tài),接受變化是不可避免的,尤其是如果你的項(xiàng)目要持續(xù)發(fā)展的話更是如此。

          要想讓你的 API 更具適應(yīng)性,其中很關(guān)鍵的一點(diǎn)就是保持盡可能薄的 API 層,真正的復(fù)雜性應(yīng)該往下層轉(zhuǎn)移。

          5API 不應(yīng)該限定實(shí)現(xiàn)

          公開的 API 發(fā)布之后,它就已經(jīng)完成了,是不可改變的,你就不能再去觸碰它了。如果你已經(jīng)有了一個(gè)設(shè)計(jì)古怪的 API,除了接受現(xiàn)狀之外,還能做些什么呢?

          你應(yīng)該不斷尋找簡(jiǎn)化實(shí)現(xiàn)的方法。有時(shí)候,你可以通過(guò)一個(gè)特定的 HTTP 頭信息來(lái)控制 API 響應(yīng)的格式,相對(duì)于構(gòu)建另外一個(gè)叫做 v2 的新 API,這是一種更簡(jiǎn)單的解決方案。

          API 只是另外一層的抽象。它們不應(yīng)該決定如何實(shí)現(xiàn),為了避免這種問(wèn)題,我們可以采用如下幾種開發(fā)模式。

           API 網(wǎng)關(guān)

          這是一種類似于門面的開發(fā)模式。如果你要把一個(gè)單體結(jié)構(gòu)拆分為一組微服務(wù),并且希望向外部暴露一些功能的話,那么你只需要構(gòu)建一個(gè)類似門面的 API 網(wǎng)關(guān)。

          它將為不同的微服務(wù)提供一個(gè)統(tǒng)一的接口(這些微服務(wù)可能有不同的 API,使用不同的錯(cuò)誤格式等等)。

           適用于前端的后端

          如果你必須要構(gòu)建一個(gè) API 來(lái)滿足一堆不同的客戶端的話,那么這可能會(huì)非常困難。針對(duì)某個(gè)客戶端所作出的決策可能會(huì)影響其他客戶端的功能。

          按照適用于前端的后端(backend for frontend)理念,如果你有不同的客戶端,它們喜歡不同形式的 API,比如移動(dòng)應(yīng)用可能會(huì)喜歡使用 GraphQL,那么就單獨(dú)為它們構(gòu)建吧。

          只有當(dāng)你的 API 是一層抽象,并且這個(gè)抽象層很薄的時(shí)候,這種方式才有效。如果它與你的數(shù)據(jù)庫(kù)耦合,或者太大,具有太多的邏輯,那么就無(wú)法這樣做了。

          6GraphQL 與 RESTful

          很多人都在熱炒 GraphQL。它是一項(xiàng)新興的技術(shù),但是已經(jīng)有了很多粉絲,以至于有些開發(fā)者聲稱它將取代 REST。

          盡管 GraphQL 比 RESTful 要新的多,但是它們有很多相似之處。GraphQL 最大的不足之處在于它的緩存,它必須要在客戶端或應(yīng)用程序中實(shí)現(xiàn)。現(xiàn)在,有內(nèi)置的實(shí)現(xiàn)了緩存功能的客戶端庫(kù)(比如 Apollo),但是這仍然要比使用 HTTP 提供的幾乎免費(fèi)的緩存功能要困難。

          https://www.apollographql.com/docs/react/caching/cache-configuration/

          從技術(shù)講,GraphQL 位于 Richardson 模型的 Level 0 層級(jí),但是它具有良好 API 的特質(zhì)。我們可能無(wú)法同時(shí)使用多個(gè) HTTP 的功能,但是 GraphQL 的出現(xiàn)就是解決這一問(wèn)題的。

          GraphQL 的殺手锏就是聚合不同的 API,并將它們作為一個(gè) GraphQL API 暴露出來(lái)。


          GraphQL 在處理數(shù)據(jù)抓取不足和數(shù)據(jù)過(guò)量抓取方面有很好的效果,而這些問(wèn)題是 REST API 很難進(jìn)行管理的。這兩個(gè)問(wèn)題都與性能有關(guān),如果數(shù)據(jù)抓取不足,那說(shuō)明你沒有高效地使用 API,所以必須要進(jìn)行大量的調(diào)用。如果數(shù)據(jù)過(guò)量抓取的話,那么 API 調(diào)用的數(shù)據(jù)傳輸會(huì)比必要的數(shù)據(jù)傳輸更大,這是對(duì)帶寬的一種浪費(fèi)。

          7小結(jié)

          借助 REST 與 GraphQL 的比較,我們能夠總結(jié)出一個(gè)好的 API 最重要的品質(zhì)。

          好的 API 的特性


          我們需要一個(gè)清晰的數(shù)據(jù)表述方式:RESTful 以資源的方式提供了表述。

          我們需要有一種方式顯示有哪些可用的操作:RESTful 通過(guò)組合資源和 HTTP 動(dòng)作實(shí)現(xiàn)這一點(diǎn)。

          我們需要有一種方式來(lái)確認(rèn)是否存在錯(cuò)誤 / 異常:HTTP 狀態(tài)碼可以實(shí)現(xiàn)這一點(diǎn),可能還會(huì)包含闡述它們的響應(yīng)信息。

          最好能夠提供 API 發(fā)現(xiàn)和導(dǎo)航的功能:在 RESTful 中,HATEOAS 負(fù)責(zé)實(shí)現(xiàn)這一點(diǎn)。

          有好的文檔是非常重要的:在這方面,可執(zhí)行、自更新的文檔可以解決這個(gè)問(wèn)題,這超出了 RESTful 規(guī)范的范圍。

          最后,但同樣重要的是,優(yōu)秀的 API 應(yīng)該具有緩存功能,除非你的特定情況認(rèn)為它是不必要的。

          REST 和 GraphQL 之間最大的區(qū)別是它們處理緩存性的方式。當(dāng)我們使用 REST 方式構(gòu)建 API 的時(shí)候,我們基本上可以免費(fèi)獲得 HTTP 的緩存功能。如果選擇 GraphQL 的話,你需要自行負(fù)責(zé)為客戶端或應(yīng)用程序添加緩存。

          來(lái)源:https://www.stxnext.com/blog/how-to-build-a-good-api-that-wont-embarrass-you

          版權(quán)申明:內(nèi)容來(lái)源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無(wú)法確認(rèn),我們都會(huì)標(biāo)明作者及出處,如有侵權(quán)煩請(qǐng)告知,我們會(huì)立即刪除并表示歉意。謝謝!





          感謝閱讀



          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香aⅴ | 国产免费又粗又大又硬又爽视频 | 乱亲伦系列短篇100视频中文 | 91极品视觉盛宴 | 一级操逼大片 |