<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?

          共 7245字,需瀏覽 15分鐘

           ·

          2021-11-05 14:59

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


          現(xiàn)在,每個人都在關(guān)注 API。API 最早開始流行于大約 20 年前,2000 年,Roy Fielding 在他的博士論文中首次提出了 REST 這個術(shù)語。同年,Amazon、Salesforce 和 eBay 向全世界的開發(fā)者介紹了他們的 API,永遠(yuǎn)改變了我們構(gòu)建軟件的方式。
          在 REST 之前,Roy Fielding 論文中的原則被稱為“HTTP 對象模型”,隨后你會明白這為何非常重要。
          隨著閱讀的深入,你還會看到如何確定你的 API 是否成熟,好 API 的主要品質(zhì)是什么以及為何在構(gòu)建 API 的時候,要注重適應(yīng)性。


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


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

          • 無狀態(tài)

          • 可緩存

          • 分層系統(tǒng)

          • 按需編碼(可選)

          • 統(tǒng)一接口

          但是,對日常使用來說,這過于理論化了。我們需要更具操作性的東西,這也就是 API 成熟度模型。


          2
          Richardson 成熟度模型


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

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


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


          Level 0 的 API 是一組簡單 XML 或 JSON 的描述。在前文中,我曾經(jīng)說過在 Fielding 的論文之前,RESTful 原則被稱為“HTTP 對象模型”。
          這是因為 HTTP 是 RESTful 開發(fā)中最重要的組成部分。REST 要盡可能多地使用 HTTP 固有屬性中的理念。
          在 Level 0,沒有使用任何這樣的東西。我們只是構(gòu)建自己的協(xié)議并把它作為一個專有層。這種架構(gòu)被稱為遠(yuǎn)程過程調(diào)用(Remote Procedure Call,RPC),適用于遠(yuǎn)程過程 / 命令。
          通常我們會有一個端點,可以對它進(jìn)行調(diào)用以獲取一堆 XML。在這方面,一個典型的例子就是 SOAP 協(xié)議:

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

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


          ?Level 1:資源


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

          其中,“/api/books”能讓我訪問一個通用的圖書目錄,“/api/profile”能夠讓我訪問這些書的作者的基本信息。為了獲取某個資源的第一個特定實例,我可以在 URL 中添加 ID(或其他引用)。
          在 URL 中還可以嵌套資源,這展示了它們是以層級結(jié)構(gòu)的形式組織的。
          回到 Slack 的樣例,如下展示了按照 Level 1 API,它們會是什么樣子的:

          現(xiàn)在,URL 發(fā)生了變化,從原先的“/api/chat.postMessage”變成了現(xiàn)在的“/api/channels/general/messages”。
          信息中“channel”部分從請求體轉(zhuǎn)移到了 URL 中。從字面就能看出,通過使用這個 URL,我們可以預(yù)期有條消息發(fā)布到了 general 通道上。


          ?Level 2:HTTP 動作


          Level 2 利用 HTTP 動作(verb)來添加更多的含義和意圖。在這方面可用的動作比較多,我這里只用到一個基礎(chǔ)的子集:PUT / DELETE / GET / POST。
          借助這些動作,我們可以預(yù)期包含它們的 URL 有不同的行為:
          • POST:創(chuàng)建新數(shù)據(jù)

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

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

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

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

          那這里的“安全”和“冪等”又是什么意思呢?
          “安全”的方法指的是永遠(yuǎn)不會改變數(shù)據(jù)的方法。REST 建議 GET 方法只能用來獲取數(shù)據(jù),所以在上面的集合中,它是唯一一個安全的方法。不管你調(diào)用多少次基于 REST 的 GET 方法,它永遠(yuǎn)不會改變數(shù)據(jù)庫中的任何東西。但是,這并不是該動作的固有特性,而是關(guān)系到你該如何實現(xiàn)它,所以我們需要確保它是這樣運行的。所有其他的方法都會以不同的方式改變數(shù)據(jù),不能隨意使用。在 REST 中,GET 方法既是安全的,又是冪等的。
          “冪等”的方法指的是多次使用不會產(chǎn)生不同結(jié)果的方法。按照 REST,DELETE 方法應(yīng)該是冪等的,如果刪除了某個資源,然后針對相同的資源再次調(diào)用 DELETE,它不會改變?nèi)魏螙|西。資源應(yīng)該早就已經(jīng)消失了。在 REST 規(guī)范中,POST 是唯一一個非冪等的方法,所以我們可以對相同的資源多次調(diào)用 POST 方法,這樣我們會得到重復(fù)的資源。
          我們重新看一下 Slack 樣例,如果我們使用 HTTP 動作來進(jìn)行更多的操作會是什么樣子:

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


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

          HATEOAS 指的是“超媒體作為應(yīng)用狀態(tài)引擎(Hypermedia as the Engine of Application State)”。
          有了 HATEOAS 之后,當(dāng)其他人使用你的 API 的時候,他們就能看到通過 API 還能做哪些其他的事情。HATEOAS 回答了“從這里出發(fā),我還能去哪里?”的問題。

          但這還不是所有的內(nèi)容。HATEOAS 還可以對數(shù)據(jù)關(guān)系進(jìn)行建模。我們可能會有一個關(guān)于圖書的資源,并且在 URL 中沒有將作者信息嵌套進(jìn)來,但是我們可以包含它們的鏈接,如果有人對作者感興趣的話,那么他們可以訪問這些鏈接并探索相關(guān)的數(shù)據(jù)。
          HATEOAS 不像其他成熟度模型的等級那樣流行,但是有些開發(fā)人員確實在使用它。其中一個樣例就是 Jira,如下是它們的搜索 API 的響應(yīng):

          他們將鏈接嵌入到了其他我們可以探索的資源中,以及該 issue 的狀態(tài)過渡列表。
          另外一個使用 HATEOAS 的樣例是 Artsy。他們的 API 嚴(yán)重依賴 HATEOAS,并且還使用了 JSON Plus 調(diào)用規(guī)范,按照該規(guī)范強(qiáng)制要求使用一種特殊的約定來構(gòu)建鏈接。下面是一個分頁的例子,這是使用 HATEOAS 最酷的樣例之一:

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


          3
          好的 API 由什么組成


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


          ?錯誤 / 異常處理


          我對自己使用的 API 的基本期望之一就是,需要有一種明確的方式來判斷是否有錯誤或異常。我想要知道請求是否得到了處理。
          HTTP 有一種簡單的方式來實現(xiàn)這一點:HTTP 狀態(tài)碼。
          管理狀態(tài)碼的基本規(guī)則是:
          • 2xx 代表一切正常

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

          • 4xx 代表客戶端做錯了某些事情

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


          我們的 API 至少要提供 4xx 和 5xx 狀態(tài)碼。有時候,5xx 是自動生成的。例如,客戶端發(fā)送了一些內(nèi)容到服務(wù)器端,但是這非法的請求,而我們的校驗是有缺陷的,從而導(dǎo)致這個問題繼續(xù)在代碼中執(zhí)行了下去,最終導(dǎo)致出現(xiàn)了異常,這樣就會返回一個 5xx 的狀態(tài)碼。
          如果你想要承諾使用特定的狀態(tài)碼,那么你會遇到“哪種狀態(tài)碼最適合當(dāng)前情況?”的問題。這樣的問題并不總是那么容易回答,我推薦你去閱讀聲明這些狀態(tài)碼的 RFC,它們給出了比其他來源更廣泛的解釋,并且告訴了你何時使用這些狀態(tài)碼更合適等。幸運的是,網(wǎng)上有些資源可以幫助我們做出選擇,比如 Mozilla 的 HTTP 狀態(tài)碼指南。
          https://developer.mozilla.org/en-US/docs/Web/HTTP/Status


          ?文檔


          優(yōu)秀的 API 必須要有優(yōu)秀的文檔。在文檔方面,最大的問題在于,隨著 API 的發(fā)展需要找人同步更新文檔。有個更好的方案是不脫離代碼自更新文檔。
          例如,注釋與代碼的脫節(jié)。當(dāng)代碼發(fā)生變化的時候,注釋依然保持不變,這樣的話,注釋就過時了。這甚至?xí)雀揪蜎]有任何注釋更糟糕,因為在隨后的一段時間內(nèi),它們會提供錯誤的信息。注釋不會自動更新,所以開發(fā)人員需要記得在維護(hù)代碼的時候同時維護(hù)它們。
          自更新的文檔工具可以解決這個問題。在這方面,一個流行的工具就是 Swagger,它是基于 OpenAPI 構(gòu)建的工具,可以很容易地描述你的 API。

          Swagger 很酷的一點在于它是可執(zhí)行的,所以如果你嘗試修改 API,能立即看到它的作用和變化。
          為了給 Swagger 添加自動更新功能,我們需要使用其他的插件和工具。在 Python 中,有針對大多數(shù)主流框架的插件。它們能生成 API 請求該如何組織的描述,并定義數(shù)據(jù)的輸入和輸出。
          如果你不想要使用 Swagger,而是想使用更簡單的工具,那該怎么辦呢?有個流行的替代方案是 Slate。
          https://slatedocs.github.io/slate/#introduction

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

          https://github.com/Mermade/widdershins

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


          ?緩存


          在有些系統(tǒng)中,緩存可能并不是什么大問題。這樣的系統(tǒng)可能沒有很多的數(shù)據(jù)可供緩存,所有的數(shù)據(jù)都在不斷地發(fā)生變化,或者系統(tǒng)根本沒有很大的流量。
          但是,在大多數(shù)情況下,緩存對于良好的性能至關(guān)重要。它與 RESTful API 密切相關(guān),因為 HTTP 協(xié)議在緩存方面做了很多事情,比如 HTTP 頭信息允許我們控制緩存的行為。
          你可能想要在客戶端緩存東西,或者如果有注冊表或值存儲的話,那么你可能想要在應(yīng)用程序中緩存數(shù)據(jù)。但是,HTTP 讓我們能夠基本上免費就可以獲得一個很好的緩存,所以如果可能的話,請不要錯過這個免費的午餐。

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


          4
          API 設(shè)計的演化


          構(gòu)建 API 以及現(xiàn)代軟件最重要的部分就是適應(yīng)性。如果沒有適應(yīng)性,開發(fā)就會變慢,在合理的時間發(fā)布特性就會變得更加困難,當(dāng)面對最后截止時間的時候更是如此。
          “軟件架構(gòu)”在不同的上下文語境中有不同的含義,不過我們現(xiàn)在采用這個定義:
          軟件架構(gòu)一種行為 / 藝術(shù),能夠避免會阻礙未來變化的決策。
          記住了這一點,在設(shè)計軟件的時候,當(dāng)你必須要在具有相似優(yōu)點的方案中做出選擇時,你應(yīng)該始終選擇更多考慮到未來的方案。
          好的實踐并不是萬能的。按照正確的方式構(gòu)建錯誤的東西并不是你想要的結(jié)果。最好采取一種成長的心態(tài),接受變化是不可避免的,尤其是如果你的項目要持續(xù)發(fā)展的話更是如此。
          要想讓你的 API 更具適應(yīng)性,其中很關(guān)鍵的一點就是保持盡可能薄的 API 層,真正的復(fù)雜性應(yīng)該往下層轉(zhuǎn)移。


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


          公開的 API 發(fā)布之后,它就已經(jīng)完成了,是不可改變的,你就不能再去觸碰它了。如果你已經(jīng)有了一個設(shè)計古怪的 API,除了接受現(xiàn)狀之外,還能做些什么呢?
          你應(yīng)該不斷尋找簡化實現(xiàn)的方法。有時候,你可以通過一個特定的 HTTP 頭信息來控制 API 響應(yīng)的格式,相對于構(gòu)建另外一個叫做 v2 的新 API,這是一種更簡單的解決方案。
          API 只是另外一層的抽象。它們不應(yīng)該決定如何實現(xiàn),為了避免這種問題,我們可以采用如下幾種開發(fā)模式。


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


          這是一種類似于門面的開發(fā)模式。如果你要把一個單體結(jié)構(gòu)拆分為一組微服務(wù),并且希望向外部暴露一些功能的話,那么你只需要構(gòu)建一個類似門面的 API 網(wǎng)關(guān)。
          它將為不同的微服務(wù)提供一個統(tǒng)一的接口(這些微服務(wù)可能有不同的 API,使用不同的錯誤格式等等)。


          ?適用于前端的后端


          如果你必須要構(gòu)建一個 API 來滿足一堆不同的客戶端的話,那么這可能會非常困難。針對某個客戶端所作出的決策可能會影響其他客戶端的功能。
          按照適用于前端的后端(backend for frontend)理念,如果你有不同的客戶端,它們喜歡不同形式的 API,比如移動應(yīng)用可能會喜歡使用 GraphQL,那么就單獨為它們構(gòu)建吧。
          只有當(dāng)你的 API 是一層抽象,并且這個抽象層很薄的時候,這種方式才有效。如果它與你的數(shù)據(jù)庫耦合,或者太大,具有太多的邏輯,那么就無法這樣做了。


          6
          GraphQL 與 RESTful


          很多人都在熱炒 GraphQL。它是一項新興的技術(shù),但是已經(jīng)有了很多粉絲,以至于有些開發(fā)者聲稱它將取代 REST。
          盡管 GraphQL 比 RESTful 要新的多,但是它們有很多相似之處。GraphQL 最大的不足之處在于它的緩存,它必須要在客戶端或應(yīng)用程序中實現(xiàn)。現(xiàn)在,有內(nèi)置的實現(xiàn)了緩存功能的客戶端庫(比如 Apollo),但是這仍然要比使用 HTTP 提供的幾乎免費的緩存功能要困難。
          https://www.apollographql.com/docs/react/caching/cache-configuration/
          從技術(shù)講,GraphQL 位于 Richardson 模型的 Level 0 層級,但是它具有良好 API 的特質(zhì)。我們可能無法同時使用多個 HTTP 的功能,但是 GraphQL 的出現(xiàn)就是解決這一問題的。
          GraphQL 的殺手锏就是聚合不同的 API,并將它們作為一個 GraphQL API 暴露出來。

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


          7
          小結(jié)


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

          我們需要一個清晰的數(shù)據(jù)表述方式:RESTful 以資源的方式提供了表述。
          我們需要有一種方式顯示有哪些可用的操作:RESTful 通過組合資源和 HTTP 動作實現(xiàn)這一點。
          我們需要有一種方式來確認(rèn)是否存在錯誤 / 異常:HTTP 狀態(tài)碼可以實現(xiàn)這一點,可能還會包含闡述它們的響應(yīng)信息。
          最好能夠提供 API 發(fā)現(xiàn)和導(dǎo)航的功能:在 RESTful 中,HATEOAS 負(fù)責(zé)實現(xiàn)這一點。
          有好的文檔是非常重要的:在這方面,可執(zhí)行、自更新的文檔可以解決這個問題,這超出了 RESTful 規(guī)范的范圍。
          最后,但同樣重要的是,優(yōu)秀的 API 應(yīng)該具有緩存功能,除非你的特定情況認(rèn)為它是不必要的。
          REST 和 GraphQL 之間最大的區(qū)別是它們處理緩存性的方式。當(dāng)我們使用 REST 方式構(gòu)建 API 的時候,我們基本上可以免費獲得 HTTP 的緩存功能。如果選擇 GraphQL 的話,你需要自行負(fù)責(zé)為客戶端或應(yīng)用程序添加緩存。

          原文鏈接:

          https://www.stxnext.com/blog/how-to-build-a-good-api-that-wont-embarrass-you

          逆鋒起筆是一個專注于程序員圈子的技術(shù)平臺,你可以收獲最新技術(shù)動態(tài)最新內(nèi)測資格BAT等大廠的經(jīng)驗精品學(xué)習(xí)資料職業(yè)路線副業(yè)思維,微信搜索逆鋒起筆關(guān)注!

          10 種常見的軟件架構(gòu)模式

          API 快速開發(fā)平臺設(shè)計思考

          老舊的 API,該如何處理?

          瞧瞧,人家那后端 API 接口寫得多優(yōu)雅!

          臥槽!我隨便寫的一個 API 竟獲得 2.5 億的訪問量

          點個在看少個 bug ??
          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  国产传媒无码 | 激情 小说 亚洲 图片: 伦 | 东方AV100在线观看 | 乐播一区二区三区 | 懂色无码 |