什麼?網絡接口還須要設計?不就是前端和後端的開發人員碰一碰,看須要什麼,就給返回什麼就行了嗎?若是需求變化,不知足了,再對接口作個修改不就行了嗎?這還須要設計?甚至在我提到「設計」這個詞的時候,某些人就笑了,技術開發還須要設計?設計不是那些作 UI 的設計師才作的事情嗎?前端
今天我來講說下我心目中的網絡接口設計是怎樣的過程?編程
接口,interface。這裏不討論它具體的定義,我給出本身對於接口比較泛的理解。小程序
首先,與接口息息相關的是一個邊界的概念。系統與系統之間,模塊與模塊之間,客戶端與服務端之間,都是有邊界的。在各個系統、模塊、端內部能夠並且應該是自成體系的,這個自成的體系與其餘體系應該有明顯的區隔,就是「邊界」。後端
其次,接口是在這個邊界上體系之間打交道創建約定。這些內部自成的體系,經過接口與對方相互的協做,造成更大的系統。每一個自成的體系,根據自身定義的功能、特性等等,與其餘體系如何協做基本是固定的。一個體系只需把協做的約定暴露出來,其餘體系按照約定來操做,就能夠實現本身的目的,而不用在意協做對象內部是怎麼作的。這就是一個接口的做用。數組
再次,接口要完成體系與體系之間的協做/通訊,是須要媒介的。如模塊與模塊之間能夠是簡單的函數調用,也多是 RPC;網絡上的各客戶端與服務端則經過網絡協議等等。安全
每一個自成體系是能夠有粒度上的大小之分的,但體系必定是有本身的邊界的。好比面向對象中講的類,也是一個體系,類對外暴露的公共方法能夠認爲是接口,類具備的功能可以與其餘類很明顯區分出其邊界。多個類相互協做能夠造成一個模塊,模塊有屬於本身的邊界;多個模塊相互協做又能夠造成更大的模塊或者子系統,子系統之間有邊界;系統之間又能夠協做造成更大的系統,系統依然有邊界。當體系與體系之間的邊界不清晰時,組成的更大的體系就會是一團亂麻,維護就很困難。咱們必定要定義好體系的邊界及體系之間協做的接口約定,讓每一個體系各司其職,又能相互協做。網絡
網絡接口,這裏具體指產品開發上服務端與各客戶端(Web,App,小程序等)之間經過 HTTP 協議進行通訊,爲了實現產品功能而作的約定。網絡接口設計首先要肯定服務端與各客戶端之間協做的具體通訊的數據格式。框架
產品開發過程當中,研發人員被分紅不一樣職能的小組進行協做。服務端有專門的人員,客戶端有專門的人員。爲了提升產品開發的效率,咱們不會像流水線同樣,讓服務端的人開發完接口之後才讓客戶端的人員開始。幾個小組的開發人員幾乎是並行的開發,而後再聯調、集成測試。有了接口的定義,肯定了具體通訊的格式,那麼各小組之間就能夠按照約定去並行的實現各自的部分,這樣就有效利用了時間。編程語言
網絡接口的設計,大部分狀況下是從前端功能需求入手的。經過接收到的需求或者產品原型,開發人員可以比較容易的知道:函數
其實這 3 點在一些人看來幾乎是網絡接口設計的所有內容了。按照這些實現,產品的功能基本能夠實現了。開發人員口頭溝通,直接編碼,相互聯調,直到接口工做正常——這正是許多創業小團隊的開發人員在作的事情。
這是遠遠不夠的!
這正是上面 3 點作的事情。
將前端的需求作好分析,基本可以知道須要哪些功能的接口才可以知足需求。大多數接口如何發起請求,須要返回什麼樣的數據,也能夠一目瞭然。由於從功能上講,服務端的大部分工做在資源的增刪改查上。
嗯,我這裏再作一個樂觀的假設,初步分析接口之後,開發人員能夠遵循 Restful 的原則,在腦海中對於如何發起請求有了概念了。
完成第一步工做之後,咱們會發現一些接口是圍繞差很少相同的實體的。好比博客系統,會有獲取博客列表,博客詳情,發表博客,編輯博客,刪除博客,獲取本身的博客等等,都圍繞博客這個實體。
雖然都是實體,因爲前端的展現不同,所須要實體的屬性也不同。好比博客列表只須要博客標題;博客詳情裏則須要博客的內容;而我收藏的博客列表可能須要一個收藏標記。
那咱們是否是直接就根據前端的須要,只返回須要的內容呢?這些內容又該怎麼返回呢?
推薦的作法是:能夠根據前端的須要返回,可是返回的應該是結構化的數據,並且不一樣類別的結構化數據數量應該儘可能少。
好比上面提到的博客,它是個實體,是有結構的。標題、內容、標籤這些都是簡單的屬性,它們組合在一塊兒造成的結構就能夠表示博客這個實體。在編程語言裏大概是類;在框架設計裏可能就是模型。
仍是拿博客舉例子。
現實中博客實體的結構比這複雜的多。上面代碼展現了 3 種可能的博客實體返回的內容,實際狀況也比這多。很顯然,這博客實體有不少共用的部分,又有不少根據特定狀況不同的部分。
若是咱們任由這幾種結構獨立的存在,服務端編碼的時候,根據須要硬編碼返回;客戶端一樣只針對接口返回的特殊字段作特殊處理。忽然有一天,博客的結構中要多返回一個建立時間,全部相關的部分可能都須要修改了。
咱們應該綜合這些結構,提取出共性的部分,造成基礎的結構,再評估特殊的部分,是整合到這個基礎的結構中,仍是提煉成新的結構。
這是一個合理的提煉結構的結果。
博客詳情在現實中是一個很複雜的結構,並且可能包含很是大的數據量(成千上萬字的內容),能夠抽成獨立的結構,做爲博客中的 detail 的內容,根據是列表仍是詳情按需返回。
收藏標記,是在個人收藏列表中須要的特殊字段,它很小,直接合併到博客實體中帶回也問題不大。
這樣系統中須要的博客實體就簡化成這兩個結構化的模型了,全部地方都能用。
你們能夠想一下,爲何把博客詳情中的字段都挪到博客結構中,這樣能夠只剩下一個模型,卻不是一個好的實踐?
寫 JavaScript/PHP 的同窗可能沒有體會到將一個結構轉換成類的痛點,在 Java/OC 這樣的強類型語言裏面定義的差很少同一實體的類型太多,就要寫不少相互轉換的代碼。作結構化,讓結構化的類別儘可能少,這在必定程度上減小了這種重複編碼。這也只是一個很是粗淺的好處。
有告終構化,其餘的好處包括:
結構化的數據是參與系統運行的基石,提煉出這些結構化的數據(實體、模型、類某種程度上來說是同樣的)纔可以更好的理解系統。
網絡接口設計,不是一個簡單而低級的步驟。須要很是的熟悉需求乃至背後的實現細節,纔可能定義出好的接口。
不一樣的接口有許多從細節出發的考量,這個環節我就舉一些例子,你們本身體會。
至少有兩種的可行方案:
顯然,這兩種方案要求服務端上的實現也不同。當你構思網絡接口設計的時候,服務端的實現已經在你腦海中有了方案。
一個任務持續 10 天,天天一次打卡,可能存在某天漏打的狀況。接口數據怎麼返回呢?
這裏我也舉兩種方案:
1. 返回一個任務打卡狀況的數組,如:
表明任務 1,第 1,3 天打卡了,第 2 天漏打了。
2. 返回一個字符串,如:1,2,4,5
,表明第 1,2,4,5 天打卡了,第 3 天漏打了,6-10 天尚未打。
這兩種接口返回數據的設計服務端的實現細節也不同。第 1 種方案可能須要一張獨立的任務打卡記錄表來支撐其實現,而第 2 種方案可能只須要在用戶任務表中加一個字段就能夠了。
不一樣的接口返回,對於客戶端上的處理也是不同的。第 1 種方案,客戶端解析對象列表;第 2 種方案,客戶端解析字符串。
這些方案如何抉擇,每一個設計者都有本身的考量。當你構思網絡接口設計的時候,服務端的實現已經在你腦海中有了方案,客戶端上怎麼處理在你腦海中也有了方案。
一樣兩種方案:
若是是針對同一實體的簡單操做接口,如針對博客的收藏/取消收藏,點贊/取消點贊,每一個都獨立一個接口,那會致使接口數量的猛增。把它們看作對實體的操做,統一爲一個接口,就能夠避免這種問題。當你構思網絡接口設計的時候,服務端的處理已經在你腦海中有了方案,客戶端上如何調用也已經在你腦海中有了方案。
用戶密碼,訂單金額,會員積分等等這些敏感數據,你的接口設計時怎麼保證安全?你想到的方案:
當你構思網絡接口設計的時候,你也已經同時在考慮這些了。
以前寫過一篇《多平臺統一用戶系統設計》,你的用戶登陸接口是僅知足目前單一平臺的登陸,仍是支持將來多平臺登陸?你該如何設計?當你構思網絡接口設計的時候,這些對將來的適應應該已經在你的腦海裏了。
在仔細揣摩這些接口實現細節時,一樣能夠概括出不少的共性出來,如用戶的登陸/受權策略,接口參數作驗籤保護,接口響應能夠有統一的結構返回、有統一的錯誤處理等等。這些統一的設計約定同樣須要記下來。
你花了不少的時間分析、思考、調研,是時候把這些重要的成果寫成文檔了。
寫成文檔有幾大好處:
一份具備良好可讀性的網絡接口設計文檔應該包含以下結構:
標題和修訂記錄就不說了。
通用說明能夠包含以下部分:
咱們在作網絡結構設計的時候,提煉出告終構化的數據,能夠稱之爲模型。將系統涉及到的模型羅列在一塊兒,可以爲理解系統提供便利。
模型的定義須要說明模型表明的實體,用來表示實體的模型名稱以及模型須要的屬性名稱和類型,併爲屬性作說明。
這裏還拿博客舉例子:
接口定義應該包括:
實例:
如今來對怎麼作接口設計作個總結:
網絡接口設計不是一個無關緊要的過程。一次好的網絡接口設計的過程,須要設計人員對整個需求有清晰的認識,甚至會考慮到實現細節上。團隊成員一塊兒參與網絡接口設計文檔的評審,是一次對需求的再次統一,是對實現細節上的一次統一。完成網絡接口設計文檔,在整個研發過程,是一個重要的里程碑。
有的朋友說作這個耗時,不值得。嗯,那你可能就要忍受快速開始開發以後反反覆覆的返工了。
- EOF -