先後端協同開發,使用 GraphQL 正確的姿式

內容來源:2018 年 06 月 09 日,有數派聯合創始人周文宇在「杭州第一屆 GraphQLParty—GraphQL與領域驅動帶來的協同價值」進行《Stratup使用GraphQL的姿式》演講分享。IT 大咖說做爲獨家視頻合做方,經主辦方和講者審閱受權發佈。前端

閱讀字數:6109 | 16分鐘閱讀web

觀看嘉賓完整演講視頻及PPT,請點擊: t.cn/EAwb3Jg

摘要

本次演講主要介紹如何使用GraphQL,分別從先後端兩個角度分析GraphQL的優劣勢,對比Restful又可以給先後端協同開發帶來哪些好處。數據庫

爲何使用GraphQL

之因此要使用GraphQL主要出於幾方面的考慮。首先咱們的業務複雜度高,應用自己的業務場景極其複雜,涉及到紡織行業大大小小几十個業務場景和十幾個不一樣工種功能之間的聯動與交互。後端

其次是因爲Tech Team有一半同事Remote在全國各地,所以對協同效率與開發工具鏈的要求很高,而GraphQL剛好能解決溝通成本的問題。第三是由於終端過於繁雜,既有b2b的平臺也有SaaS產品和硬件產品,各個終端的鏈接很是多,若是用傳統的Restful API開發會用到很是多的膠水代碼。數組

傳統接口的問題(後端)

這裏大概介紹一下傳統接口在咱們這個領域中應用所會遇到的一些問題。緩存

溝通成本高。先後端須要反覆溝通接口結構和數據類型,可是對於B端這種相對複雜的業務場景,數據和業務場景都是多變的。同時前端對數據接口結構的掌控有限,先後端Pipeline也不一致,傳統BBF對前端不夠友好,更多的還得依賴後端。安全

開發效率低。文檔維護成本高,一致性和同步性問題很難解決。服務器

一些技術債。好比對多終端和多場景支持不友好,缺少標準化的約束,先後端都須要重複工做。微信

以上是從後端的角度來對這些問題進行的分析,接下來由咱們的前端方面的負責人介紹下咱們在前端方向上的一些實踐。數據結構

傳統接口的問題(前端)

剛纔周老師已經從後端的角度分析了這些痛點,我這裏就從前端的層面來從新談論下這些問題。

第一個要提的是反覆溝通接口的問題,對於後端來講他們更關注的是數據的表結構,而前端所須要的僅僅是界面的展現數據。有時這些數據並不可以從某個表中直接獲取到,可能要跨不少的表,這就須要前端和後端之間進行相互的磨合溝通才能得到最終的結果。

其次是前端對接口的結構掌控有限,當前端的請求發送出去後,接口所返回的數據形式有可能並不符合預期,好比本該返回的數組變成了對象。

再來看下開發效率低的問題。前端開發中UnderFetching和OverFetching一直沒法避免。

UnderFetching指的從接口中取到的數據遠低於須要展示的數據,由此引起了N+1問題,即須要根據已取得的接口中的ID或者詳細信息再去請求對應的接口,這就致使了前端的請求從異步變成了同步。

本來頁面的渲染時間是取決於最慢的接口響應時間,而同步模式下則是全部接口串行返回的時間。OverFetching則正好相反,接口的返回數據遠高於須要展示的數據,對前端和服務器端的資源形成了雙重消耗。

Node中間層 vsGraphQL(前端)

面臨傳統接口所帶來的這些痛點,通常團隊都會選擇NodeJs做爲中間層的解決方案。那麼Node和GraphQL相比有那些優缺點呢?下面來一塊兒看下。

Node.js在必定程度上減輕了underFetching和overFetching問題,尤爲是解決了N+1的問題,後端能夠經過Node.Js中間層來進行數據資源的整合,可是此時仍舊只能返回一個固定的數據結構。

Node.js缺陷也很明顯,好比對多端須要作額外的適配,難以適應前端的快速迭代,須要花費大量時間維護,由此還會引起接口文檔的斷層。

GraphQL對於Node碰到的這些問題基本上都可以很好的解決。GraphQL中能夠由前端來定義Query,頁面和數據能完美匹配。同時一旦Schema肯定,先後端就能夠快速並行開發。前端對字段及返回類型也可以瞭如指掌,GUI清晰的展示了字段的類型結構。

如何給高速運行的汽車更換輪子(前端)

給高速運行的汽車更換輪子是一件至關危險的事情,而咱們早期所面臨的狀況和這差很少。當時咱們的產品已經推出有一段時間了,數據庫很是龐大,功能也很繁雜,並且數據徹底是基於Restful。此時須要將Restful徹底替換成GraphQL,這無疑對先後端來講都是一個很是大的挑戰。

在跟換輪子以前,我先比較了一下前端數據緩存的框架,目前主流的有Relay和Apolloo。Relay由Facebook官方推出,支持的框架有React和React Native,Apolloo則支持絕大多數主流框架。

Router方面Relay官方支持React Route,新版本中還支持一個新的路由Found。Apollo因爲自己的運行方式和生命週期已經徹底和路由割離開,因此可以支持任何Route。

Relay的數據緩存由官方提供的RelayStore完成,Apollo則是基於Redux。基於以上幾點考慮,我最終選擇了Apollo。

以前咱們在使用Redux加Redux-saga的時候,倒沒有遇到什麼特別大的問題,主要仍是特別麻煩。須要手動管理和存儲返回數據,還要爲每一個資源創建一套Action,Reducer,Redux-saga,同時要針對每一個請求進行異常及數據處理,針對頁面須要的數據觸發屢次串行請求。

在使用GraphQL和Apollo以後,前端方面只須要全局定義一個URL,接下來就是定義每一個Query須要取得的數據,根據頁面定製接口數據。同時還能夠作全局的異常處理,接口請求的合併。

如何安裝輪子(前端)

接下來將講一下我是如何安裝輪子的,會涉及到一些面向場景的解耦操做,還有具體的代碼演示。

對於咱們應用的訂單頁面數據,在Restuful場景下首先會根據訂單ID請求訂單信息,接着依據從訂單信息中獲得的產品ID獲取產品詳細數據,以後還須要根據建立人ID獲取客戶詳細數據,最後將這些數據結合起來才能渲染頁面。

上圖展現的是經過GraphQL來作訂單頁面時後端定義的一些類。最下方的員工類是一個基類,它包含了id、性別、部分、姓名這些通用的字段。

Employee對象被嵌套在Order類和Peuduct類中,在這兩個類中可以很輕易的經過creator字段獲取到Employee的數據信息。

而Order類和Peuduct類之間是相互引用的關係,經過items字段分別定義對應的對象數據。

這張圖分別展現了前端Fragment和Query。前端Fragment是基於對象的,左邊的第一段代碼就是一個基於Employee對象的employee Fragment,咱們能夠從中獲取到的id、gende、name等數據。在其餘的Fragment中可以自由的引用employee對象。

Query其實就是GraphQL對傳統前端Fragment的定義,它可使用GraphQL官方提供的方法將關聯的數據字段綁定給某個component。

鑑權及續租方案(前端)

在結合GraphQL和Apollo的狀況下咱們的鑑權方案主要依賴於AppAsyncStorage和web localStorage這兩個數據可持久化的方案。

在登陸過程當中產生的token緩存到App AsyncStorage或web localStorage中,註冊GraphQL Server的時候經過outLink來setContext,setContext方法主要用來重寫header,在header中添加資源字段。這個資源字段通常是和後端商議後決定,不過Apollo官方的推薦經過傳入token來實現整個鑑權方案。

如何使用輪子

工業控制設備(前端)

前面提到過咱們的終端設備中還包含樹莓派,這是一個工業控制設備,通常被放置在用戶的廠房中,用來打印記錄庫房數據。

咱們經過阿里雲物聯網套件來實現服務器端和樹莓派之間的通訊,設備能夠發佈和訂閱一些數據到MQTT中 ,每隔一段時間就會有心跳包從設備上傳到MQTT,以此來更新頁面數據。以後MQTT會將心跳包傳遞到消息隊列中,而後再經過API到應用層來同步消息。

最後app端或web端經過暴露給他們的GraphQLAPI來讀取到設備的信息,好比設備編號、固件版本、公網內網IP等。

當用戶發現設備版本和服務器版本存在差別,執行須要更新的時候,本質上是發送動態操做到GraphQL API層,而後由GraphQL API層發送消息到設備 ,以後消息經過SDK API到達MQTT,接着發佈一系列的請求到設備。最後設備重啓完成以後會再從新發布心跳包到MQTT來更新一系列的操做。

使用輪子過程當中的注意事項

使用新輪子的問題(前端)

在使用新輪子的過程當中碰到的第一個問題就是在學習成本和團隊適應方面。一是文檔不夠不夠健全,相關的學習資料偏少,可能產品已經推出了2年時間,可是文檔倒是剛推出時寫的。

除開文檔問題以外,本質上還有一個思路的改變。原先使用Redux發送請求時,雖然和後端溝通麻煩了一點,可是畢竟已經和熟悉了。如今轉換到GraphQL後,請求發起機制、數據刷新、文件上傳等等都徹底不一樣,至關於要從頭開始學習新的東西。

在使用Apollo的過程當中咱們也遇到了一些坑。好比屢次請求觸發致使返回結果爲underfined,之因此會這樣是因爲第一個接口請求發送出去後,還在loading階段時,同一個接口又發送了第二次,致使返回數據發生衝突變成undefined。

還有資源對象和id重複致使資源數據被覆蓋的問題,這是由Apollo的數據存儲的特性所形成的,Apollo的每一個資源對象的類型和id是定義數據字段惟一的標識。

Component的設計思路改變(前端)

之前設計的Component有容器組件和展現組件這兩個概念,容器組件和Redux store之間存在交互,用來更新數據,展現組件則是單純的展現數據。如今使用GraphQL以後,咱們發現了一個更優的解決方案。

由於每一個對象的資源字段固定,徹底可讓每一個Component和GraphQL 的Query片斷一一對應。這意味着Component再也不是爲了請求而定義的,而是根據對象類型來定義

過於依賴Fragment致使的性能問題(前端)

咱們在使用GraphQL 的過程當中曾出現過一次很是大的性能問題。當時爲了更高效的開發,咱們將每一個資源對象所有使用Fragment來寫,且每一個對象都取到了全部頁面中所有的數據。

此時一個要動態計算的字段被放在了一個基類中,在多個Fragment中循環調用,甚至嵌套調用。這時候後端就可能接收到一個須要計算n方次動態計算的結果的請求,服務器的負載壓力可想而知。

以上這種狀況對於前端來講,操做的只是某個實體的一個或幾個資源字段。可是對於後端來講,每一個實體背後可能對應着不一樣的數據庫甚至不一樣類型的存儲集羣,同時後端集羣間的海量數據自由join獲得的結果。前端氾濫數據會致使後端負載急劇上升。

以上大概就是前端方面要講的所有內容,接下請繼續看下關於後端方面的問題。

使用新輪子的問題(後端)

使用GraphQL的過程當中遇到的第一個比較嚴重的問題就是接口設計思路轉變困難,以前在寫RestfulAPI的時候想的更多的是面向資源,而GraphQL的設計思路則是面向場景,這徹底顛覆了後端設計接口的哲學。

其次是開發feature時要更多考慮性能的問題,避免被查宕機。另外GraphQL相比Restful在鑑權模型設計上要投入更多的精力。

說完了這些弊端,再來看下有那些有利的地方。一是接口開發工做量大幅減小,重複性工做得以減小,避免了出錯。其次是錯誤返回和文檔等標準化工做能夠藉助工具自己完成。最後是對API多版本管理更加友好。

性能問題(後端)

從後端來看早期的性能問題都是由於急於快速上線引發的,主要有如下幾個因素。

第一點就是GraphQL的N+1場景,即前端在查詢數據的時候可能首先要查到IDS數組,而後再map IDS數組從新對後端發起請求,最後後端經過多條SQL取到的多是列表數據。

第二點是在前期開發的時候沒有作請求層級限制,致使前端查詢多層嵌套,服務器沒法承受壓力。

第三點是沒有作分頁的數目限制,通常來講前端能夠經過傳遞特定的參數給接口來設置每頁的接收數量,可是有些前端人員可能會爲了快速上線新功能將每頁的數量直接設置爲9999,這樣服務器就又會被搞宕機。

安全問題

爲避免發生一些安全問題,須要在認證、受權和請求頻率限制幾個方面多加註意。認證上每次都要在Header上加上token,認證機制應改成JWT,咱們這邊因爲涉及到的終端較多,因此還會按平臺檢驗合法性。

受權上能夠針對操做也能夠針對字段進行具體的受權。請求頻率限制上既要防止惡意刷請求也要實現基於IP和UserID的限制。

安裝工人的心得

這裏的標題是安裝工人的心得,其實指的就是我我的在使用GraphQL過程的一些感悟和總結。

先來看看GraphQL還有那些弊端。

第一,雖而後端已經作了一些優化,可是仍是沒有徹底實現前端的按需查詢,當數據量達到必定級別的時候,數據庫查詢可能會成爲性能瓶頸。

第二,生態羣並不完善,文檔和實例缺少,可能在google查詢到的資料沒法確切的解決問題。

第三,評價一個技術的實用性,不光要看技術力還要看它可否快速落地。一個現有的項目要從Restful切換到GraphQL,其實重構的壓力很大,且重構和業務並行推動困難。

第四,因爲目前國內使用GraphQL的團隊不是不少,因此很難招聘到有經驗的工程師,須要從零開始積累。

談完了弊端再來講下我的的感悟,總結起來就是三個確實。確實提高了先後端的協做開發效率;確實下降了在先後端協做過程當中的錯誤率;確實提升了接口複用度和開發效率。

我的認爲用開發工具自己提升不管是前端、後端仍是DevOps的工做效率是將來的發展趨勢,我也相信GraphQL將來會支持更多的框架,解決更多的問題,並在性能和安全上有進一步提高。

關於咱們

有數派是專業的紡織SaaS產品,具有工業(硬件)控制、樣品管理、倉庫存儲、銷售管理、設計輔助等功能,應用場景覆蓋了行業幾十個場景,近十個終端。

咱們在技術棧的選擇上,web用的是React,App用的React Native,後端主要的API源是用Ruby寫的,還有部分Python用來作數據分析,目前全部的API都被遷移到了GraphQL上。硬件部分用到了C++,服務器的容器管理用的是Docker,DB則是PostgreSQL。

咱們目前在終端上有樹莓派、tv、pad、web、app、微信端、ipad。

以上爲所有分享內容,謝謝你們!

編者:IT大咖說,轉載請標明版權和出處

相關文章
相關標籤/搜索