Web API設計方法論

作者: Mike Amundsen  來源: infoQ  發布時間: 2015-02-15 10:43  閱讀: 6943 次  推薦: 4   原文鏈接   [收藏]  

  英文原文:A Web API Design Methodology

  Web設計、實現和維護API不僅僅是一項挑戰;對很多公司來說,這是一項勢在必行的任務。本系列將帶領讀者走過一段旅程,從為API確定業務用例到設計方法論,解決實現難題,并從長遠的角度看待在Web上維護公共API。沿途將會有對有影響力的人物的訪談,甚至還有API及相關主題的推薦閱讀清單。

  這篇 InfoQ文章是 Web API從開始到結束系列文章中的一篇。你可以在這里進行訂閱,以便能在有新文章發布時收到通知。

  設計Web API不止是URL、HTTP狀態碼、頭信息和有效負載。設計的過程--基本上是為了你的API“觀察和感受” -- 這非常重要,并且值得你付出努力。本文簡要概括了一種同時發揮HTTP和Web兩者優勢的API設計方法論。并且它不僅對HTTP有效。如果有時你還需要通過WebSockets、XMPP、MQTT等實現同樣的服務,大部分API設計的結果同樣可用。可以讓未來支持多種協議更容易實現和維護。

  優秀的設計超越了URL、狀態碼、頭信息和有效負載

  一般來說, Web API設計指南的重點是通用的功能特性,比如URL設計,正確使用狀態碼、方法、頭信息之類的HTTP功能特性,以及持有序列化的對象或對象圖的有效負載設計。這些都是重要的實現細節,但不太算得上API設計。并且正是API的設計--服務的基本功能特性的表達和描述方式--為Web API的成功和可用性做出了重要貢獻。

  一個優秀的設計過程或方法論定義了一組一致的、可重復的步驟集,可以在將一個服務器端服務組件輸出為一個可訪問的、有用的Web API時使用。那就是說,一個清晰的方法論可以由開發人員、設計師和軟件架構師共享,以便在整個實現周期內幫助大家協同活動。一個成熟的方法論還可以隨著時間的發展,隨著每個團隊不斷發現改善和精簡過程的方式而得到精煉,卻不會對實現細節產生不利的影響。實際上,當實現細節設計過程兩者都有清晰的定義并相互分離時,實現細節的改變(比如采用哪個平臺、OS、框架和UI樣式)可以獨立于設計過程。

  API設計七步法

  接下來我們要對Richardson和Amundsen合著的《REST風格的Web API》一書中所介紹的設計方法論做簡要地概述。因為篇幅所限,我們不能深入探討這一過程中的每一步驟,但這篇文章可以讓你有個大概的認識。另外,讀者可以用這篇概述作為指南,根據自己組織的技能和目標開發一個獨有的Web API設計過程。

  說明:是的,7步看起來有點兒多。實際上清單中有5個步驟屬于設計,額外還有兩個條目是實現和發布。最后這兩個設計過程之外的步驟是為了提供一個從頭到尾的體驗。

  你應該計劃好根據需要重新迭代這些步驟。通過步驟2(繪制狀態圖)意識到在步驟1(列出所有組成部分)有更多工作要做。當你接近于寫代碼(步驟6)時,可能會發現第5步(創建語義檔案)中漏了一些東西。關鍵是用這個過程暴露盡可能多的細節,并愿意回退一步或者兩步,把前面漏掉的補上。迭代是構建更加完整的服務畫面以及澄清如何將它暴露給客戶端程序的關鍵。

  步驟1 : 列出所有組成部分

  第一步是列出客戶端程序可能要從我們的服務中獲取的,或要放到我們的服務中的所有數據片段。我們將這些稱為語義描述符。語義是指它們處理數據在應用程序中的含義,描述符是指它們描述了在應用程序自身中發生了什么。注意,這里的視點是客戶端,不是服務器端。將API設計成客戶端使用的東西很重要。

  比如說,在一個簡單的待辦事項列表應用中,你可能會找到下面這些語義描述符:

  • id : 系統中每條記錄的唯一標識符
  • title : 每個待辦事項的標題
  • dateDue : 待辦事項應該完成的日期
  • complete : 一個是/否標記,表明待辦事項是否已經完成了。

  在一個功能完備的應用程序中,可能還會有很多語義描述符,涉及待辦事項的分類(工作、家庭、園藝等),用戶信息(用于多用戶的實現)等等。不過為了突出過程本身,我們會保持它的簡單性。

  步驟2 : 繪制狀態圖

  下一步是根據建議的API繪制出狀態圖。圖中的每個框都表示一種可能的表示--一個包含在步驟1中確定的一或多個語義描述符的文檔。你可以用箭頭表示從一個框到下一個的轉變--從一個狀態到下一個狀態。這些轉變是由協議請求觸發的。

  在每次變化中還不用急著指明用哪個協議方法。只要標明變化是安全的(比如HTTP GET),還是不安全/非冪等的(比如HTTP.POST),或者不安全/冪等的(PUT)。

  說明:冪等動作是指重復執行時不會有無法預料的副作用。比如HTTP PUT,因為規范說服務器應該用客戶端傳來的狀態值替換目標資源的已有值,所以說它是冪等的。而 HTTP POST是非冪等的,因為規范指出提交的值應該是追加到已有資源集合上的,而不是替換。

  在這個案例中,我們這個簡單的待辦事項服務的客戶端應用程序可能需要訪問可用條目的清單,能過濾這個清單,能查看單個條目,并且能將條目標記為已完成。這些動作中很多都用狀態值在客戶端和服務器之間傳遞數據。比如add-item 動作允許客戶端傳遞狀態值title和dueDate。下面是一個說明那些動作的狀態圖。

  這個狀態圖中展示的這些動作(也在下面列出來了)也是語義描述符-- 它們描述了這個服務的語義動作

  • read-list
  • filter-list
  • read-item
  • create-item
  • mark-complete

  在你做這個狀態圖的過程中,你可能會發現自己漏掉了客戶端真正想要或需要的動作或數據項。這是退回到步驟1的機會,添加一些新的描述符,并/或者在步驟2中改進狀態圖。

  在你重新迭代過這兩步之后,你應該對客戶端跟服務交互所需的所有數據點和動作有了好的認識和想法。

  步驟 3 : 調和魔法字符串

  下一步是調和服務接口中的所有“魔法字符串”。“魔法字符串” 全是描述符的名稱--它們沒有內在的含義,只是表示客戶端跟你的服務通訊時將要訪問的動作或數據元素。調和這些描述符名稱的意思是指采用源自下面這些地方的,知名度更高的公共名稱:

  這些全是明確定義的、共享的名稱庫。當你服務接口使用來自這些源頭的名稱時,開發人員很可能之前見過并知道它們是什么意思。這可以提高API的可用性。

  說明:盡管在服務接口上使用共享名稱是個好主意,但在內部實現里可以不用(比如數據庫里的數據域名稱)。服務自身可以毫不困難地將公共接口名稱映射為內部存儲名稱。

  以待辦事項服務為例,除了一個語義描述符- create-item,我能找到所有可接受的已有名稱。為此我根據Web Linking RFC5988中的規則創建了一個具有唯一性的URI。在給接口描述符選擇知名的名稱時需要折中。它們極少能跟你的內部數據存儲元素完美匹配,不過那沒關系。

  這里是我的結果:

  經過名稱調和,我的狀態圖變成了下面這樣:

  步驟 4 : 選一個媒體類型

  API設計過程的下一步是選一個媒體類型,用來在客戶端和服務器端之間傳遞消息。Web的特點之一是數據是通過統一的接口作為標準化文檔傳輸的。選擇同時支持數據描述符(比如"identifier"、"status"等)和動作描述符(比如"search"、"edit"等)的媒體類型很重要。有相當多可用的格式。

  在我寫這篇文章時,一些頂尖的超媒體格式是 (排名不分先后):

  • 超文本標記語言 (HTML)
  • 超文本應用程序語言(HAL)
  • Collection+JSON (Cj)
  • Siren
  • JSON-API
  • 交換表達式的統一基礎 (UBER)

  讓所選擇的媒體類型適用于你的目標協議也很重要。大多數開發人員喜歡用HTTP 協議做服務接口。然而WebSocketsXMPPMQTTCoAP 也會用--特別是對于高速、短消息、端到端的實現。

  在這個例子中,我會以HTML為消息格式,并采用HTTP協議。HTML有所有數據描述符所需的支持(<UL>用于列表, <LI>用于條目, <SPAN>用于數據元素)。它也有足夠的動作描述符支持 (<A>用于安全鏈接, <FORM method="get">用于安全轉變, <FORM method="post">用于非安全轉變)。

  注意:在這個狀態圖中, 編輯動作是冪等的(比如HTTP PUT),并且HTML仍然沒有對PUT的原生支持。在這個例子中,我會添加一個域來將HTMLPOST做成冪等的。

  好了,現在我可以基于那個狀態圖創建一些樣例表示來“試試”這個接口了。對我們的例子而言,只有兩個表示要渲染:“待辦事項列表”和“待辦事項條目”表示:

  1 :用HTML表示待辦事項列表集合

  圖2:用HTML表示待辦事項條目

  記住,在你做狀態圖的表示樣例時,可能會發現之前的步驟中有所遺漏(比如漏掉描述符,動作描述符中有冪等之類的變化等)。那也沒關系。現在就是解決所有這些問題的時機-- 在你把這個設計變成代碼之前。

  等你對表示完全滿意之后,在開始寫代碼之前還有一個步驟--創建語義檔案。

  步驟 5 : 創建語義檔案

  語義檔案是一個文檔,其中列出了設計中的所有描述符,包括對開發人員構建客戶端和服務器端實現有幫助的所有細節。這個檔案是一個實現指南,不是實現描述。這個差別很重要。

  服務描述符的格式

  服務描述文檔格式已經出現了相當長一段時間了,并且當你想給已有的服務實現生產代碼或文檔時很方便。確實有很多種格式。

  在我寫這篇文章時,頂級競爭者有:

  檔案的格式

  現在只有幾種檔案格式。我們推薦下面兩種:

  這兩個都比較新。JSON-LD規范在2014年早期達成了W3C推薦狀態。Hydra仍是一個非官方草案(本文寫成時還是),有一個活躍的開發者社區。ALPS仍處于IETF的早期草案階段。

  因為檔案文檔的理念是要描述一個問題空間的現實生活方面(不只是那一空間中的單一實現),所以其格式跟典型的描述格式十分不同:

  3 : ALPS格式的待辦事項列表語義檔案

  你會注意到,這個文檔就像一個基本的詞匯表,包含了待辦事項服務接口中所有可能的數據值和動作--就是這個理念。同意遵循這個檔案的服務可以自行決定它們的協議、消息格式甚至URL。同意接受這個檔案的客戶端將會構建為可以識別,如果合適的話,啟用這個文檔中的描述符。

  這種格式也很適合生成人類可讀的文檔,分析相似的檔案,追蹤哪個檔案用得最廣泛,甚至生成狀態圖。但那是另外一篇文章的課題了。

  現在你有完整的已調和名稱的描述符清單,已標記的狀態圖,以及一個語義檔案文檔,可以開始準備編碼實現樣例服務器和客戶端了。

  步驟 6 : 寫代碼

  到了這一步,你應該可以將設計文檔(狀態圖和語義檔案)交給服務器和客戶端程序的開發人員了,讓他們開始做具體的實現。

  HTTP服務器應該實現在第2步中創建的狀態圖,并且來自客戶端的請求應該觸發正確的狀態轉變。服務發送的每個表示都應該用第3步中選好的格式,并且應該包含一個第4步中創建的指向一個檔案的鏈接。響應中應該包含相應的超媒體控件,實現了在狀態圖中顯示、并在檔案文檔中描述的動作。客戶端和服務器端開發人員在這時可以創建相對獨立的實現,并用測試驗證其是否遵守了狀態圖和檔案。

  有了穩定的可運行代碼,還有一步要做:發布。

  步驟 7 : 發布你的API

  Web API應該至少發布一個總能給客戶端響應的URL -- 即便是在遙遠的將來。我將其稱為“看板URL” --每個人都知道的。發布檔案文檔也是個好主意,服務的新實現可以在響應中鏈接它。你還可以發布人類可讀的文檔、教程等,以幫助開發人員理解和使用你的服務。

  做好這個之后,你應該有了一個設計良好的、穩定的、可訪問的服務運行起來了,隨時可以用。

  總結

  本文討論了為Web設計API的一組步驟。重點是讓數據和動作描述正確,并以機器可讀的方式記錄它們,以便讓人類開發人員即便不直接接觸也能輕松為這個設計實現客戶端和服務器端。

  這些步驟是:

  1. 列出所有組成部分

    收集客戶端跟服務交互所需的所有數據元素。

  2. 繪制狀態圖

    記錄服務提供的所有動作(狀態變化)

  3. 調和魔法字符串

    整理你的公開接口以符合(盡可能)知名的名稱

  4. 選擇媒體類型

    評審消息格式,找到跟目標協議的服務轉變最貼近的那個。

  5. 創建語義檔案

    編寫一個檔案文檔,定義服務中用的所有描述符。

  6. 寫代碼

    跟客戶端和服務器端開發人員分享檔案文檔,并開始寫代碼測試跟檔案/狀態圖的一致性,并在有必要時進行調整。

  7. 發布你的API

    發布你的"看板URL"和檔案文檔,以便其他人可以用他們創建新的服務以及/或者客戶端程序。

  在你的設計過程中,你可能會發現有遺漏的元素,需要重做某些步驟,以及要做一些折中的決定。這在設計過程中出現得越早越好。將來開發人員要求用新的格式和協議實現時,你還有可能用這個API設計。

  最后,這個方法論只是為Web API設計過程創建一種可靠、可重復、一致的設計過程的一種可能方式。在你做這個例子時,可能會發現插入一些額外的步驟,或者縮減一些會更好用,并且-- 當然 -- 消息格式和協議決策在不同案例中可能也會發生變化。

  希望這篇文章能給你一些啟發,讓你知道如何給自己的組織以及/或者團隊創建一個最佳的API設計方法論。

4
0
 
標簽:Web API 設計 API
 
 

文章列表

arrow
arrow
    全站熱搜

    大師兄 發表在 痞客邦 留言(0) 人氣()