API 演進:從 REST 到 GraphQL 的變化

以往為了滿足各種需求開發了各式各樣API,總覺得可以稱得上會開發API了,不曾想打開求職網站開出的API條件都是...

前言

早期在開發 php 的時候並沒有甚麼 RESTful API、GraphQL、還是 RPC 這些專有名詞,但是都曾因需求實作過類似的架構,只是當時沒甚麼在意這些定義而已,甚至哪裡會特別提 API 這個詞彙,就只是 URI 接口或資源而已…

例如 PHP 只用 GET 跟 POST 來區分帶在瀏覽器網址上或是參數中,並且也會用統一接口的概念,例如操作使用者通通都是 …/api/user.php 但是參數利用 $_POST["action"] 決定要處理的 function 是哪個 insert、update、還是 delete

但為了讓複雜或不同的系統環境可以有些共通的溝通方式,逐漸把一些慣用的作法定義下來或是標準化,本文介紹API的演進,但與其說演進不如說,只是隨著需求不同、系統規模變大變複雜而選擇較適合的架構而已,並沒有誰最好,或是誰將取代誰的目的。

API

API 全名為 Application Programming Interface,其定義是「API 是一組定義兩個系統之間如何溝通的介面規範,它讓不同應用或服務之間能交換資料與功能,不需要了解彼此內部實作。」—參考自 MDN API

就像天氣熱的時候你拿著冷氣遙控器按下電源打開,就能獲得冷空氣,不需要你自己去了解冷氣機是怎麼運做才能產生冷空氣,這個遙控器就是冷氣提供給你用的API,而且你如果拿著A廠牌的遙控器想操作B廠牌的冷氣有很大的可能會失敗,因為各家產出的API可能因為部分規格不同而不能通用。

RESTful API or REST API

有的人念 Restful API 有的人念 REST API,為了搞清楚這名詞我們要先拆開來看其定義。

REST(Representational State Transfer)是一種架構風格,不是具體的實作。當 API 符合 REST 的設計原則,才稱為 RESTful API。

什麼是 Representational

當使用者瀏覽網頁時,網頁嘗試透過 API 呼叫 SERVER 取得存放在資料庫的資源時,SERVER 會以 JSON, 或 XML之類的格式回傳時,這種讓資源以某種代表來展現就是 Representational 的含義,這也是REST頭兩個字母RE的含義

什麼是 State Transfer

我們先來看下面的情境,當你每天為了趕時間每天到早餐店都是固定點做最快的餐點,幾次後老闆就會記得你都點一樣的,於是在看到你時就會直接問跟上次一樣嗎,這時就是老闆將你要點的內容也就是把你的狀態給記下來了。

有一天老闆請了新的廚師在廚房裡只負責出餐,這時候你每次來就得自己填單送給後面廚房,此時狀態就回到了你的身上,而REST架構風格要求客戶端的狀態不保存在服務端,因此客戶端要自己負責在每一次請求都正確地表示自己的狀態給服務端。

REST 核心

REST 價購的核心就在這兩點 REpresentational: 資源的表示性 State Transfer: 狀態傳輸

REST 約束

  • 客戶端服務端: 各自獨立
  • 統一接口:
    • 不同的資源用不同的 URI 表示
    • 請求時表明方法,利用不同連接方式 GET/POST/PUT/PATCH/DELETE
  • 無狀態:服務端不保存狀態,以提高性能
  • 緩存: 避免客戶端短時間內連續請求同一資源,影響頻寬及響應時間,GET 預設緩存
  • 分層系統:允許經過負載平衡後進行流量分配
  • 按需代碼(Optional):服務端可以回傳可執行代碼(ex. Javascript)給客戶端,以此擴充客戶端功能

REST 的缺點

  • 依賴文檔: 沒有文檔的幫助,只能在黑暗中摸索
  • 過度獲取(Over-fetching): 返回的內容經常超出實際所需要,造成網路浪費
  • 獲取不足(Under-fetching): 返回的內容不足還需要二度查詢,導致整體耗時

而 GraphQL 的出現,便解決了 REST 很多問題

GraphQL

GraphQL 是由 Facebook 在 2015 年開源的一種查詢語言與伺服器端 runtime,目的是解決 REST API 在複雜應用場景下常遇到的資料過多(Over-fetching)或資料不足(Under-fetching)問題。

核心概念

  • 單一 Endpoint:GraphQL 使用單一的 /graphql endpoint,不再以資源為單位拆分 URI。
  • 精確查詢:前端可以自行定義需要的欄位,伺服器只會回傳請求的資料,避免資料冗餘。
  • 型別系統:GraphQL 使用 Schema 定義 API 的型別結構,查詢與回應都有明確的型別驗證,開發上更可預期。
  • 即時 API 文件:開發工具如 GraphiQL 可以即時查詢 schema,不再需要手動維護 API 文件。
  • Query / Mutation / Subscription:
    • Query:查詢資料
    • Mutation:修改資料
    • Subscription:訂閱資料變動(支援即時更新)

解決 REST 缺點

問題 REST GraphQL 解法
資料過多 回傳整個物件 精確指定欄位
資料不足 需要多次 API 請求 一次查詢多層資料
文件維護困難 靠 Swagger 或手動 自動生成文件 + 開發工具支援
多 Endpoint 管理 每個資源一個路由 單一 /graphql 統一處理
前端需要等候端改動 每次需要異動前端都要等候端調整完 Schema 隨時都是最新的版本

缺點與取捨

  • 學習成本:需要熟悉型別系統與查詢語言語法
  • 後端實作較複雜:Schema 設計與 Resolver 撰寫需額外投入
  • 快取難度較高:相較於 REST 的 GET 緩存,GraphQL 因查詢多樣性,需搭配額外快取策略(如 persisted queries)

結論

在我看來所謂的 Schema 或是 API 只是一組定義好的資料格式給前後端看 前端看到的是他能取得甚麼資料"名稱" 後端看到的是他必須提供甚麼資料"名稱",以及這名稱所對應的資料是怎麼收集或計算出來的而已 因此最辛苦的還是後端建立 GraphQL 的人,且前期必須投入一定的成本,設計出菜單(schema)以及資料製造過程是怎麼處理(resolve)的。

例如,在沒有此架構前,呼叫 WordPress API 時,若使用預設 function 取德的資訊如果不足或太多,就會根據呼叫 API 時參數下 hook 插入資訊或過濾不必要資訊,藉此減少網路消耗、或者作者單次呼叫就取得所需資訊。

另外,GraphQL 一直強調,可以透過一次呼叫完成原本多次呼叫的缺點,但老實說原本網頁發展出 ajax 全名 Asynchronous JavaScript and XML(非同步JavaScript與XML技術),本就是為了避免單次連線處理過久,而進行分散加速的作法,現在給了前端方便,後端就又要在負載平衡以及分散系統上下更多工夫了。

所以採用任何架構之前還是要經過詳細的評估。

API的演進路上還有 RPC / gRPC / tRPC 等,目前實務上尚未實作到,先不探討,未來有機會再繼續。

Reference

▶️ 【API技术核心原理】REST | GraphQL | gRPC | tRPC

▶️ 為什麼要學 GraphQL?傳統 RESTful API 不好嗎?

Gemini – 探索 WordPress GraphQL 實作