后端應該提供兩套 API,一套是外部使用的通用 API,服務特定的數據,另一套是自家使用的應用 API,服務特定的頁面。
在當今的web開發中,構建一個提供JSON服務的后端和一個渲染應用程序的前端是很流行的。我不太喜歡,但還好。但是如果你認為你的后端需要被設計成一個通用的公共API是不行的。這不會節省你的時間。
為什么不喜歡呢?
當你設計一個通用API時,你必須弄清楚一堆煩人的東西。
- 如何預測和啟用所有可能的工作流
- 如何避免N+1請求的尷尬工作流程
- 如何測試每個可能的請求的功能、性能和安全性
- 如何在不破壞現有工作流的情況下更改API
- 如何在內部需求和公共需求之間確定API變更的優先級
- 如何記錄每件事,以便各方都能完成工作
在前端,還有很多:
- 如何收集呈現頁面所需的所有數據
- 如何優化對多個端點的請求
- 如何避免以非預期的方式使用API數據字段
- 如何權衡新功能的好處和新API請求的成本
如果你只是為前端制作后端,這些真的是你的問題嗎?你是否必須想象每一個可能的工作流程,避免N+1請求問題,測試每個請求配置,或者在確切知道每個頁面應該是什么樣子的情況下拒絕使用自己的功能?你們可以看出我的意思。
那有什么建議呢
我建議你不要再把你的前端當成一些通用的API客戶端,而是把它當成你應用的一半。
想象一下,如果你可以將整個“page”的JSON值發送給它。為/page/a
創建一個端點,并在那里渲染/page/a
的整個JSON。對每一頁都這樣做。不要強迫你的前端開發人員發送一堆單獨的請求來渲染復雜的頁面。不要用人為的限制來煩他們。
在那個JSON中,實際渲染頁面。不要渲染抽象的模型和集合。渲染具體的框、節、段落、列表。渲染可視化頁面結構。
{"section1": {"topBoxTitle": "Foo","leftBoxTitle": "Bar","linkToClose": "https://…"},"section2": {…}
}
這與服務器驅動的UI類似但不完全相同。也許我們可以稱它為服務器通知的UI。
怎么做會更好呢?
你見過上面那些煩人的決定嗎?首先,他們現在已經走了。
其次,你現在可以自由決定“我想要頁面 a”,然后在后端和前端實現“頁面 a”。超級簡單。
不再有“我們需要引入什么API工作流才能讓這個頁面幾乎成為可能?”。你可以讓“頁面 a”保持沉默,只做它需要做的事情。你把“第一頁”的漏洞,安全性,性能都測試了個遍。你甚至可以在一個簡單的SQL查詢中獲取“頁面a”的所有內容。你可以緩存“頁面 a”的整個JSON負載。
前端確切地知道“頁面 a”有效載荷中的每個字段的用途。在字段含義上沒有差異。它們完全代表了前端的需求。
當項目干系人告訴你修改“頁面a”時,你可以直接修改“頁面a”,而不是花很多時間來弄清楚后端API如何適應“頁面a”的更改。它不是API請求編排的集合。只是“第1頁”。你已經將自己從自己強加的API限制中解放出來。
您的業務邏輯現在已經從隨意地在前端和后端之間劃分為僅后端。你的前端終于可以專注于表現和UI了。你的后端最終可以專注于實現所需的功能。有點像目標,不是嗎?
你真的試過這個嗎
是的,到目前為止,我已經在幾個生產項目中嘗試過這種方法。其中一個是個人原因,另一個是在現有公司中持續多年的重構工作。整個團隊都被說服了,結果很好。我們遇到的唯一問題是前端團隊變得越來越無聊。幾乎所有的業務邏輯都被剝奪了。與此同時,后端團隊并沒有感到“興奮”。一切都變得有點無聊。不知怎么的,我們最終都討論了更多的業務而不是代碼。
如果你被說服了,請隨時停止閱讀。下一部分是對我不斷聽到的各種反駁的回應。
但我希望我的前端團隊有自由!(或者我希望我的前端解耦!)
老實說,你的前端沒有自由。當他們向你發送7個請求來渲染一個頁面時,這不是自由。這是為了滿足基本要求而跳的。一旦需求改變,您可能需要改變后端來適應它。自由都是偶然的,而且大多是在錯誤的地方。
如果你真的想給予你的前端團隊自由,直接在Postgres上安裝GraphQL包裝器,然后退出。
但我們實際上想要一個通用API,所以這是一石二鳥,不是嗎?
不,您實際上并不希望將此API公開。你以為你會,但到了時候,你會說“糟了,也許我不應該”。這兩個API有非常不同的原因來改變。公共API需要啟用客戶端的工作流。私有后端需要啟用您的產品經理的下一個心血來潮。別再把棍子塞進你自己的自行車輪子里了。
但是在為頁面構建JSON時,我將如何重用邏輯呢?我在我的CRUD控制器中重用了這么多邏輯!
如果你的編程語言允許重用邏輯(它確實如此),那么你就可以重用邏輯。使用合成,繼承,任何你需要使用的東西。如果你自己做了一些好的抽象,那么你將有一個驚人的時間從你的樂高積木組合在一起頁面。
但我們也可以將此API重用到移動的應用程序中!
您的移動的應用程序有一組不同的頁面,其中包含不同的信息、結構和更改原因。您將保存更多的時間和理智為它制作另一個后端專門。但是,嘿,你可以重用很多邏輯(見上一段)。
但是,如果頁面需要部分XHR更新怎么辦?我總是要返回一整頁嗎?
不,創建一個只返回特定內容的端點是可以的。我允許你去。為特定頁面部分的數據片段創建端點或其他內容。沒事了,我沒事了從初始負載渲染React組件,然后通過XHR調用對這些端點進行更新。但只有在某些頁面上需要它們時才引入這些端點。這些都是例外情況,而不是默認情況。
但是我的前端是SPA,所以它幾乎總是需要數據片段,而不是整個頁面
這些數據片段仍然可以作為部分頁面結構而不是通用資源來提供。只要你的后端只服務于前端的確切需求,你就很好。