EP9 - 十分鐘解密GraphQL

Meta 當初還是 Facebook時候 發現一個瓶頸是常常會over fetching or under fetching

很多頁面或component需要的資料很像但因為那個API就是給這麼多東西而我只需要一點點

很多資源就被浪費掉了 比如網路頻寬畢竟當時的data還沒有現在這麼快

或是有些component需要很多API來湊齊需要的資料就會等很久

當然也可以一個API叫這些 這完全是OK的

不過就是不太flexible

long story short 最後開發了GraphQL

GraphQL其實是個query language

如果你只有GraphQL的話它本身其實沒辦法給你什麼

GraphQL後面需要接東西

它強大的地方是面對前端只有一個API gateway

我要什麼query都是和一個簡單來說server溝通

但GraphQL可以根據這個query 看你怎麼接 和其他Rest API拿或是和資料庫拿甚至只是一個JSON檔案

組成

GraphQL有很多公司有做比如Prisma和Apollo

我現在和前公司都是用Apollo所以講的東西有可能是Apollo才有但大致上那個idea應該是差不多的

GraphQL有三個components

schema, resolver, data source

schema: query, mutation

在RESTful世界中有GET POST這類的method

在GraphQL裡面任何取資料的method都是query

而需要增加或是修改資料的都是mutation

定義完這些後你需要定義這些query mutation拿的input和return的data structure長什麼樣子

類似REST裡面的parameter和response

這些都寫在一個graphql檔案裡面

下一步是

resolver: schema進來 query進來 GraphQL應該要把這個query match到哪一個data source

data source: 資料來源從哪裡來 比如另一個Rest API, database, or 另一個GraphQL server

基本上我們就是傳一個fetch 或是 gRPC request把data傳回resolver把這些資料和schema接起來

優點

GraphQL的特點是我的query想要返回多少data比如我user只要id和email

我拿到的就是只有id和email而不會連帶其他東西都來

浪費頻寬也浪費memory

今天我若需要發三個不同的query

我可以在前端把三個query寫在同一個request上面

我們就只要傳一個request就好而不是做三個個別的request

把和server交流的時間省了下來

另一個特點是discoverability, 每個GraphQL產品應該都有帶Introspection

會告訴你說有什麼query可以用 input是什麼然後schema是什麼

這本身就是一個API document

想要什麼query就先找看看有沒有類似的

沒有我們再來加

這邊就得特別提一下Apollo有個產品or功能就是Federation

可以有很多個subgraph但對外面來說都是一個graph

這和micro services特色蠻像的 也可以單獨的做deployment和publish

不管graph有多少個或是schema有多大 前端只要面對一個api server就好了

我今天找到的query可能不是我們組寫的而是別的組寫的

如果這資料結構是你要的你就可以直接用了而不用請後端寫一個給你

這就是我所謂的被發現的能力

我自己是不希望在每個endpoint的Swagger上面ctrl F找我要的API

在schema裡面除了每個data都定義一個type比如integer, string這樣

我們也會自定義自己的type

而且這些type是可以被share的不管是自己組的或是別人的graph

我如果今天有個User type

我可能有個query是單純return使用者資料

另一個是回傳購買紀錄但裡面也有個user資料

雖然兩個不同的team但我們可以共用這個type

這對溝通來說幫助很大而且我們前端也能很快地掌握這到底確切有什麼資料

缺點

每個技術都有它的缺點所以GraphQL也不例外

對一個小專案來說GraphQL其實有點複雜

和REST api相比之下你得做很多準備才能吧GraphQL弄好而這只是後端這邊的

前端也得把Apollo Client弄好而且如果還有用TypeScript你可能也會希望把type弄好

什麼都還沒開始弄就已經滿頭大汗準備下班了

然後等新人來再教他們這些東西

那個learning curve應該稍微抖一點

GraphQL standard都是用POST來傳這些request的而且99%的status code都是200

意味著caching可能是個問題 大部分的infra都不會cache POST

Apollo有方法把request轉成GET所以還算是個解決方案

但status code都是200可能會造成一些小困擾

雖然Apollo Client是回傳error object因為GraphQL把error放在repsonse裡面
但有些error reporting會去看這個status code 代表你前端想debug去看reporting時候可能不會看到說哪個query其實報錯了

得多做一步去後端看一下

雖然不是特別大的問題 就有些人可能會覺得怪怪的

結論

要不要採用GraphQL我覺得這不算是一個單純的技術問題而是管理上的問題

公司裡面組之間有沒有明確的責任和domain規範

GraphQL能不能幫你們做到更好的組織和管理

上述說的東西其實REST都可以做到

只是今天就是回歸到那個問題我們要解決什麼痛點

有個Pattern叫backend for frontend
GraphQL是個非常貼切的例子

GraphQL schema比較是為了前端設計的而不是資料庫的table設計的

它就是一個類似data transformation layer

要在前端做這些也可以

把多個rest api response在前端整理一下再顯示

但若有很多個app這麼做就挺浪費時間

而且這種事情在server上做比較簡單也快

如果你喜歡這內容的話幫我在 Twitter 和 Threads 上面分享給其他正在前端這條路上努力的朋友們,也別忘了訂閱我們電子報收到第一手消息喔 🚀