GraphQL:
重新定義 API 互動
不再被 REST 的多個 Endpoint 所困擾。學習如何讓前端精確定義所需的資料,並透過 Apollo Server 打造高效能的 API 層。
為什麼我們需要 GraphQL?
在傳統的 REST API 中,前端開發者經常面臨兩個頭痛的問題:Over-fetching 與Under-fetching。
Over-fetching
你只需要使用者的姓名,但 /api/user/1 卻回傳了包含地址、電話、幾百行歷史紀錄的龐大 JSON,造成頻寬浪費。
Under-fetching
你想顯示一篇貼文和其作者資訊,必須先打 /api/post/1 拿到作者 ID,再打一次 /api/user/ID。這種 N+1 請求讓載入變慢。
GraphQL 的解法:精確請求
前端直接描述它想要的資料結構,伺服器保證只回傳那些欄位,且一次請求就能拿到所有巢狀資料。
一、Schema:定義你的資料契約
GraphQL 是強型別的。在寫任何程式碼之前,你必須使用 SDL (Schema Definition Language) 定義資料模型。
! 代表該欄位為必填 (Non-Null)。二、Resolvers:資料的加工廠
Schema 只是「規格」,真正的邏輯寫在 Resolvers。每個 Schema 中的欄位,都對應到一個 Resolver 函數,負責去資料庫、快取、甚至另一個 API 抓取資料。
警告:N+1 查詢陷阱
如果上面的 `Post.author` 被呼叫了 100 次(當你請求 100 篇貼文時),這會導致資料庫被查詢 101 次。 這在 REST 裡是常見問題,在 GraphQL 裡如果你不注意,會變得更嚴重。
三、DataLoader:快取與批次處理
為了解決 N+1 問題,我們使用 Facebook 開源的 DataLoader。 它的原理是:在一個 Tick 內收集所有的 ID,然後用一個 `WHERE IN (id1, id2...)` 的 Query 一次抓回來。
四、Apollo Client:前端的狀態管理
在 React 中,Apollo Client 不只是發送請求的工具,它還是一個強大的「本地快取」。它會自動把抓回來的資料根據 `__typename` 和 `id` 進行正規化 (Normalization)。
五、Subscriptions:即時資料流
GraphQL 內建支援 Subscriptions,底層通常透過 WebSocket 實作。這對於即時聊天室、股票行情或通知系統非常完美。
GraphQL vs REST:該如何選擇?
| 特性 | REST API | GraphQL |
|---|---|---|
| 資料獲取 | 固定結構,容易 Overfetch | 精確請求,絕不浪費 |
| 進入點 | 多個 URL (End-points) | 單一 URL (/graphql) |
| 強型別 | 需依賴 Swagger/OpenAPI | 原生 Schema 支援 |
| 快取 | 優秀 (基於 HTTP Cache) | 較困難 (需依賴 Client Cache) |
總結:給初學者的話
GraphQL 不是為了取代 REST,而是為了解決「複雜前端應用」與「多樣化資料需求」而生的。如果你正在開發一個大型、資料關係緊密的專案,GraphQL 會是你的救星。