精品国产一级在线观看,国产成人综合久久精品亚洲,免费一级欧美大片在线观看

Coursera的GraphQL之旅

責任編輯:editor004

作者: Bryan Kane

2017-12-07 11:27:54

摘自:INFOQ

在Coursera,前端開發人員非常喜歡GraphQL的靈活性、類型安全和社區支持,但后端開發人員卻不怎么直接接觸GraphQL。

Bryan Kane講述了Coursera是如何在他們的生產環境使用GraphQL的。以下內容翻譯自作者的博客,查看原文:Coursera’s journey to GraphQL。

在Coursera,前端開發人員非常喜歡GraphQL的靈活性、類型安全和社區支持,但后端開發人員卻不怎么直接接觸GraphQL。

在過去的一年,我們開發了一些工具將REST API轉成GraphQL,這樣后端開發人員就可以繼續開發他們熟悉的API,而前端開發人員可以通過GraphQL訪問他們想要的數據。

在這篇文章里,我們將介紹我們的GraphQL之旅以及在這一過程中經歷的成功與失敗。

初始調研

Coursera的REST API都是基于資源的,比如課程API、導師API、年級API等。這些API的開發和測試都很容易,而且在后端提供了非常好的關注點分離。不過,隨著產品規模的增長,API的數量也在增長,我們開始面臨一系列問題,如性能問題、文檔問題和易用性問題。我們發現很多頁面需要四到五個網絡來回才能獲取到必要的數據。

那個時候,我們有超過1000個不同的REST端點(現在則更多),從REST到GraphQL的遷移成本是巨大的。所有后端的服務間通信都使用了REST API,而且后端服務為前端和其他后端服務暴露出來的是同一套API。我們有三種客戶端(Web、iOS和Android)。

經過調研,我們找到了一種可以采用GraphQL的方案——我們決定在REST API之上增加一個GraphQL代理層。這種方式已經很常見了,并有,所以這里就不再詳述。

在生產環境使用GraphQL

我們先是構建了一個新的GraphQL處理器,然后在生產環境啟動了一個GraphQL服務器用于向REST端點發起調用,并將數據展示在演示頁面上。經過幾天的測試,我們確定這個方案是可行的。

短暫的成功

我們從這個項目中學到了一個教訓,就是不要高興得太早。

GraphQL服務器在頭幾天很穩定,但在我們向團隊演示數據頁面那天,所有的GraphQL查詢都失敗了。這個讓我們有點措手不及,因為從上次確認這個方案可行之后,就沒有動過GraphQL服務器。

后來我們發現,下游的課程目錄服務為了修復一個不相關的bug回滾到了前一個版本,導致GraphQL服務中的schema出現不一致。我們很快修復了schema問題,但我們也意識到,當GraphQL的schema規模增長到1000個并由50多個不同的服務來支撐的時候,要保持一切都同步是不可能的事情。在微服務架構里,如果有多個事實來源(source of truth),那么出現不同步是遲早的事。

自動化流程

于是我們試圖尋找如何能夠實現單個事實來源的解決方案——我們完全可以將REST API作為事實來源,因為我們的GraphQL schema就是基于這些API定義的。所以,我們需要自動化、決策性地構建我們的GraphQL層,體現出當前架構里正在運行的東西,而不是我們的臆想。

幸運的是,我們的REST框架為我們提供了所需的一切:

每個服務為我們提供動態的REST資源清單。對于每一種資源,我們可以檢查它們的端點和參數(比如,課程可以通過id獲取到,或者通過導師查詢到)。我們可以收到由我們的Courier Schema Language為每個模型定義的Pegasus Schema。

我們在GraphQL服務器上設置了一個任務,每五分鐘ping一次下游的服務,獲取所有必要的信息,然后在Pegasus Schema和GraphQL類型之間構建一對一的轉換層。

接下來,我們使用之前開發的處理器邏輯在GraphQL查詢和REST請求之間建立映射,得到一個全功能的GraphQL服務器,其更新速度的落后時間不會超過五分鐘。

關聯資源

我們使用GraphQL最主要的原因之一就是希望能夠為頁面一次性獲取到必要的數據。不過,我們最初的方案只提供了REST API到GraphQL之間一對一的映射。如果不將資源關聯起來,我們仍然需要進行多次GraphQL查詢。盡管開發者體驗得到了提升,但在性能方面并沒有獲得實際的好處。

我們的REST API都是一個個孤島,但在使用了GraphQL之后,模型和資源需要對彼此有所了解,因為它們之間存在必要的關聯。

資源之間并不會自動構建鏈接,所以我們定義了一個簡單的注解,開發人員可以將它加在資源上面,用于指定資源之間的關系。例如,一個課程資源需要有一個導師字段,表示教授該課程的導師是誰。我們可以使用課程里的導師ID獲取導師信息。我們稱之為“前向關系”,因為我們知道使用ID可以獲得哪些導師的信息。

courseAPI.addRelation( "instructors" -> ReverseRelation( resourceName = "instructors.v1", finderName = "byCourseId", arguments = Map("courseId" -> "$id", "version" -> "$version"))

如果我們想從一個資源跳到另一個資源,但又沒有顯式指定鏈接,那么可以使用反向查找。比如,為了找出某個用戶的某一門課程的注冊信息,我們可以在userEnrollments.v1資源上調用byCourseId,這樣就可以返回某個用戶在某門課程上的注冊信息。

有了這些鏈接,Coursera的所有數據和資源就形成了一個網絡。

結論

我們在Coursera的生產環境運行GraphQL服務器超過六個月的時間,雖然道路仍然崎嶇,但GraphQL為我們提供的幫助無所不在。開發人員操作數據變得更加容易,GraphQL提供的類型安全特性也讓我們的網站變得更可靠,使用GraphQL加載數據也更快。

鏈接已復制,快去分享吧

企業網版權所有?2010-2024 京ICP備09108050號-6京公網安備 11010502049343號

  • <menuitem id="jw4sk"></menuitem>

    1. <form id="jw4sk"><tbody id="jw4sk"><dfn id="jw4sk"></dfn></tbody></form>
      主站蜘蛛池模板: 十堰市| 农安县| 太原市| 张家界市| 纳雍县| 涟源市| 开远市| 比如县| 昌都县| 阆中市| 砚山县| 中方县| 集安市| 绵竹市| 都昌县| 景宁| 封开县| 融水| 蚌埠市| 乐业县| 佛教| 长沙县| 共和县| 集贤县| 全椒县| 日照市| 岳普湖县| 崇明县| 高安市| 苍南县| 林西县| 巴林左旗| 宿松县| 浦东新区| 新竹市| 宁国市| 虎林市| 黔西县| 革吉县| 绥芬河市| 奇台县|