API 設計 — 好的 API 設計有什麼特點?

2024年9月16日

💎 加入 E+ 成長計畫 與超過 400+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

相信不論是前端、後端,或者是全端工程師的讀者,對於 API 這個概念都不陌生。對於後端與全端的開發者來說,設計與開發 API 是日常工作中相當重要的環節之一;在接下來幾篇文,我們將會著重在 API 設計這個主題,一同來探討如何設計好 API。

這一篇文章我們會先從:

  • 為什麼要有 API?
  • 好的 API 有什麼特點談起

在下一篇文會談設計 API 時有哪些該特別注意的要點;而下下一篇進一步拉到資深工程師的角度,談如何優化團隊的 API 設計流程、與整體 API 品質。

API 是什麼? 為什麼要有 API?

由於多數讀者已經熟知 API 是什麼,我們在這邊不重複做基本的介紹(不清楚的可以看下方相關文章)。

不過想回到本質與大家一同思考,API 是什麼? 為什麼要有 API?

透過 API 避免重複造輪子

讓我們先用多數人熟知的汽車為例,來做一個類比。在硬體的世界中,相信多數人都對供應鏈並不陌生。

以造車為例,今天 Toyota 或 Ford 要造一輛車,不會所有的東西都自己做,而是會跟上游的供應商買部分的零件,在有了來自不同供應商提供的零件後,根據自己的設計來造出一台車。

而 API 就像軟體世界的供應鏈,當有了 API,軟體團隊不再需用什麼東西都自己開發,透過 API 就能夠完成某些特定的任務。

舉例來說,如果想要存圖片,可以呼叫 AWS S3 的 API,免去自己手動去開發複雜的雲端存儲系統;又或者是想要做生成式 AI 的應用,可以直接呼叫 OpenAI 的 ChatGPT API,這樣能免去自己訓練 LLM 的時間與精力。

從本質來看,API 是把一個系統模組化的方式。我們可以把系統拆分成不同的模組,而不同的模組由不同的 API 來提供相關功能,S3 的 API 提供存儲功能、OpenAI 的 API 提供 AI 功能,而 Stripe 的 API 提供金流功能,系統這樣拆分後就變得容易管理與維護,同時也不用什麼都自己重新造輪子。

透過 API 整合系統

除了讓開發者們免於重新自己造輪子,API 的另一個存在目的,是可以協助整合不同系統。透過 API,我們能把一個大的系統拆解成小的子系統 (或說模組),而不同的模組,彼此交互的介面就是 API。

從前端與後端分離的角度來看,API 也扮演重要的角色。傳統來說,可以把所有的操作都寫在後端,然後每次使用者有任何與應用程式的互動,都交給後端處理後,傳送一個全新的 HTML 給前端;但在加入 API 的概念後,可以把前端與後端視為不同的模組,然後兩者透過 API 整合在一起,兩者透過 API 互動。

近年來業界也有一種叫 API 先行 (API-first) 的做法,所謂的 API 先行是指在進到任何的實際開發工作前,會先設計好 API。舉例來說,前後端之間會先共同討論,把 API 的規格都設計好後,然後才進到實際的開發工作中。這樣做的好處,是可以確保 API 的品質與易用性;這是對比過往可能後端都開發完 API 後才找前端對,結果發現對前端來說不好用,導致需要花額外時間重新設計與修改。

好的 API 設計有什麼特點?

推薦平常有在開發 API 的讀者,可以用下面這些要點來檢視,看看自己開發的 API,是否有符合好的 API 設計該有的要點 (備註:以下的要點,是取自於業界中不同的資深工程師分享,且僅取一再被不同人重複提到的;因此為最核心的特點,而非窮盡所有特點)。

簡單直觀

API 設計要簡單直觀,API 的任務是讓使用它的開發者能夠成功。從這個角度看,如果 API 設計得複雜,讓使用該 API 的開發者覺得難用,甚至無法順利用,那這個 API 將無法達到其存在目的。簡言之,讓人容易學會怎麼用,是 API 設計最重要的原則之一。

先前在社群上有一個激烈的討論,是知名獨立開發者 levelsio 批評 Google 的 AI API 太難用,連用之前的設定都很難(如下圖);相比之下 OpenAI 的 API 只需要一個指令就能直接用,兩者極大的差別,讓人不想用 Google 的 API。該推文獲得極大的迴響,因為許多開發者都有同感。

levelsio 批評 Google 的 AI API 太難用的推文
levelsio 批評 Google 的 AI API 太難用的推文
圖片來源:https://x.com/levelsio/status/1831836883829322156

從這可以說明,API 夠不夠簡單好用,影響是很巨大的。特別是當開發的產品本身就是 API 時 (例如這些大型語言模型,都是靠 API 來賺錢),這時 API 不夠簡單好用,對於商業會有很直接的衝擊。

進一步說,直觀的意思是讓人可以不用額外思考。要做到讓人不用特別思考,可以透過以下方式做到:

一致性要高

同一個系列的 API 一致性高,就可以讓消費 API 的人不用適應不同的風格,當東西用起來足夠熟悉,就會讓人覺得直觀,不用花額外的心力去思考。

舉例來說,今天同一個團隊出了兩個 API,都是要移除資源的 API,然而一個是 remove 開頭,另一個是 delete 開頭,當要用的開發者看到,就會疑問說為什麼會有兩種不同的命名? 這是典型的不一致的狀況。

從一致性高的角度來看,除非真的有不同含意,不然不要有多個不同的單詞來代表同樣的意思。以這邊來說,removedelete 假如是指同一種操作,挑一個用就好。

要做到一致性高,有另一個簡單的方式,是遵循業界常見的規範。舉例來說,如果有個 URI 原本都回傳 200,但某天突然回傳 301,用的人不用特別思考,也可以知道該資源被永久換去其他地方。

延續這個觀點,在 API 設計上有一個推薦的方式叫「入境隨俗」。因為許多 API 會需要支援多種不同程式語言,在設計時,要入境隨俗,依照該程式語言的規範做調整。

舉例來說,目前多數的生成式 AI 的 API 都同時支援 Python 與 Node.js,但這兩種語言的許多規範不同,在設計時就需要因應來調整,這樣讓分別用這兩種語言的開發者,在串接 API 時,就可以更直觀地完成。

總的來說,當一致性高,意味就會少;當 API 的使用者不容易感到意外,就會相對難用錯,也會讓 API 更好用。

命名可讀性

命名上的可讀性高,也可以讓使用該 API 的開發者更輕鬆。一個推薦的原則是,命名要能夠解釋該 API 在做什麼。當能做到這樣,API 就容易讓人一看就懂;或是反過來說,讓想用某個 API 的開發者,能夠在去查看 API 文件前,就輕易猜到想用的那支 API 會叫什麼名字。

談到可讀性,就不能不談命名的重要。很多時候,開發者在命名時,很常會從技術的角度出發來定義與命名,而不是從使用者的角度來思考命名,這種做法會很容易讓 API 讓人難以理解。

先前 Stripe 的技術長有分享,他們曾經開發一支處理 Issuer Fraud Record 的 API,在實際上線前的小規模測試時,發現許多使用者不清楚這支 API 在做什麼,因為不知道 Issuer Fraud Record 是什麼。去做了一些調查與調整後,他們重新命名成 Early Fraud Warning 大家瞬間就懂,原來這支 API 是用來偵測並警告潛在的詐騙。

一支 API 做一件事

在設計 API 時,要盡量避免某支 API 包山包海,而是盡量做到讓一支 API 就做一件事,然後把這件事做好。這樣才能讓使用者容易使用。

換句話說,API 的範圍要盡可能窄,不要想要把什麼功能、參數都加進來。業界有一句話叫 When in doubt, leave it out,意思是當你有所遲疑,在想要不要把某個東西放進 API 時,這時就應該把該東西排除,不要放進去。通常來說,後續要新增會比較容易,但要移除通常比較困難,所以在一開始就想包山包海,不僅使用者可能覺得難用,也可能讓後續維護困難。

有個可以檢視的方法,是問自己「能不能輕易為該 API 命名? 以及能不能輕易解釋該 API 的功能?」 如果沒辦法做到這兩件事,那很可能是參雜了多個不同的功能在一起。

閱讀更多

如果你對好的 API 設計這主題感興趣,我們在 E+ 有更完整講解的版本,除了「簡單直觀」這個要點外,我們還談了其他的重要原則。有興趣的讀者,歡迎加入 E+ 成長計畫。

本文為 E+ 成長計畫的深度內容,截取段落開放免費閱讀。歡迎加入 E+ 成長計畫閱讀完整版本 (點此了解 E+ 的詳細介紹)


🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們