API 設計的關鍵:精準界定 API 邊界

更新 發佈閱讀 18 分鐘

大家好!今天我們要討論的是 API 設計中的一個關鍵步驟——界定 API 邊界。這個過程就像是在建造一個圖書館之前,先確定每個區域的用途:哪些地方是放書的、哪些地方是供人閱讀的,以及哪些地方需要與其他部門協作。通過合理界定 API 的邊界,我們可以確保 API 的功能既精確又高效,避免陷入過度設計或欠缺設計的陷阱。


1.什麼是API邊界?

API 的邊界決定了它的功能範圍,就像圖書館的功能區劃一樣。清晰地界定 API 的邊界,不僅能夠幫助你專注於 API 的核心功能,還能避免捲入不必要的複雜性和業務耦合,從而提高系統的靈活性和可維護性。

我們先來反向思考一下:如果 API 沒有明確的邊界,會變成什麼樣子?

沒有邊界的 API:多合一反模式

假設今天你要為公司開發一個客戶管理系統,這個系統需要對公司客戶進行 CRUD 操作(Create, Read, Update, Delete),具體需求包括:

  1. 查詢單筆客戶
  2. 查詢多筆客戶
  3. 新增客戶
  4. 修改單筆客戶
  5. 批次修改客戶
  6. 刪除單筆客戶

如果我們不清楚地界定 API 的邊界,而是選擇一個「多合一」的 API 來處理這些需求,那麼 API 可能會設計成這樣:

public class Customer
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}

public class ApiResult
{
public bool Success { get; set; }
public string Message { get; set; }
public List<Customer> Customers { get; set; }
public Customer SingleCustomer { get; set; }
}

public ApiResult CustomerAction(List<Customer> customers, string actionType)
{
switch (actionType)
{
case "GetSingle":
// 查詢單筆客戶邏輯
break;
case "GetMultiple":
// 查詢多筆客戶邏輯
break;
case "Create":
// 新增客戶邏輯
break;
case "UpdateSingle":
// 修改單筆客戶邏輯
break;
case "UpdateBatch":
// 批次修改客戶邏輯
break;
case "Delete":
// 刪除客戶邏輯
break;
default:
return new ApiResult { Success = false, Message = "無效的操作類型" };
}

return new ApiResult { Success = true, Message = "操作成功" };
}

或許部分初學者會覺得這不就是switch case 的用法,根據Type來分類並執行他的動作,但若是把詳細的各動作邏輯都寫出來,程式碼的閱讀性會變的非常糟糕。不妨看看下面這個將邏輯部分完整呈現的範例:

public class Customer
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}

public class ApiResult
{
public bool Success { get; set; }
public string Message { get; set; }
public List<Customer> Customers { get; set; }
public Customer SingleCustomer { get; set; }
}

private List<Customer> _customers = new List<Customer>();

public ApiResult CustomerAction(List<Customer> customers, string actionType, string customerId = null)
{
switch (actionType)
{
case "GetSingle":
var customer = _customers.FirstOrDefault(c => c.Id == customerId);
if (customer == null)
{
return new ApiResult { Success = false, Message = "客戶不存在" };
}
return new ApiResult { Success = true, Message = "查詢成功", SingleCustomer = customer };

case "GetMultiple":
return new ApiResult { Success = true, Message = "查詢成功", Customers = _customers };

case "Create":
foreach (var newCustomer in customers)
{
_customers.Add(newCustomer);
}
return new ApiResult { Success = true, Message = "新增成功" };

case "UpdateSingle":
var existingCustomer = _customers.FirstOrDefault(c => c.Id == customerId);
if (existingCustomer == null)
{
return new ApiResult { Success = false, Message = "客戶不存在" };
}
existingCustomer.Name = customers[0].Name;
existingCustomer.Email = customers[0].Email;
return new ApiResult { Success = true, Message = "更新成功" };

case "UpdateBatch":
foreach (var updatedCustomer in customers)
{
var customerToUpdate = _customers.FirstOrDefault(c => c.Id == updatedCustomer.Id);
if (customerToUpdate != null)
{
customerToUpdate.Name = updatedCustomer.Name;
customerToUpdate.Email = updatedCustomer.Email;
}
}
return new ApiResult { Success = true, Message = "批次更新成功" };

case "Delete":
var customerToDelete = _customers.FirstOrDefault(c => c.Id == customerId);
if (customerToDelete == null)
{
return new ApiResult { Success = false, Message = "客戶不存在" };
}
_customers.Remove(customerToDelete);
return new ApiResult { Success = true, Message = "刪除成功" };

default:
return new ApiResult { Success = false, Message = "無效的操作類型" };
}
}

看到這一大陀的程式碼,如果要針對特定的功能進行測試與修改,你要先能一眼找出要修改的點變的非常困難,更何況上述還不是很完整的處理商業邏輯,還是非常省略過後的程式。因此我們能看到

沒有邊界的 API 帶來的問題

這種多合一的 API 設計看起來很方便,所有的操作都集中在一個方法中。然而,這種設計會帶來以下問題:

  1. 可讀性差: 隨著功能的增多,CustomerAction 方法的代碼將變得越來越長,難以維護。每次新增或修改功能,都需要改動這個方法,容易引入錯誤。
  2. 高耦合度: 不同的業務邏輯被耦合在一起,任何一個操作的改變都可能影響到其他操作,導致代碼的穩定性下降。
  3. 難以測試: 由於所有操作都集中在一個方法中,對這個方法進行單元測試時需要考慮多種情況,測試複雜度大大增加。
  4. 無法擴展: 當你需要為客戶管理系統新增更多功能時,這個多合一 API 的複雜性會成倍增長,最終導致代碼難以擴展。

有邊界的 API 設計:分而治之

為了解決上述問題,我們需要明確 API 的邊界,將不同的操作分散到不同的 API 方法中。這樣,每個 API 只負責一項具體的功能,既清晰又易於維護。

public ApiResult GetCustomerById(string id)
{
// 查詢單筆客戶邏輯
}

public ApiResult GetCustomers()
{
// 查詢多筆客戶邏輯
}

public ApiResult CreateCustomer(Customer customer)
{
// 新增客戶邏輯
}

public ApiResult UpdateCustomer(Customer customer)
{
// 修改單筆客戶邏輯
}

public ApiResult UpdateCustomers(List<Customer> customers)
{
// 批次修改客戶邏輯
}

public ApiResult DeleteCustomer(string id)
{
// 刪除單筆客戶邏輯
}

有邊界的 API 帶來的好處

  1. 清晰的結構: 每個 API 方法只負責一項具體任務,代碼結構清晰,易於閱讀和理解。
  2. 低耦合度: 不同的業務邏輯被分開,修改某一個功能時,不會影響到其他功能,代碼更穩定。
  3. 易於測試: 由於每個 API 方法只負責一個功能,測試變得簡單,能夠專注於測試單一功能的正確性。
  4. 良好的可擴展性: 當需要新增功能時,可以輕鬆地添加新的 API 方法,而不會影響到現有的功能。

上面的程式範例,還不是主流的架構設計下的程式碼範例,帶篇幅慢慢帶到,會一步一步將程式碼修正到較好的架構與設計。


2. 如何界定 API 邊界?

界定 API 邊界涉及多個步驟,從理解業務需求到識別核心資源,再到劃分功能責任。這些步驟幫助我們構建一個精確且靈活的 API,能夠滿足業務需求而不會過度膨脹。

  1. 理解業務需求: 首先,你需要深入理解 API 所服務的業務領域。這意味著你必須清楚地了解業務流程,以及哪些功能是 API 必須支持的。例如,在圖書館管理系統中,圖書的借閱和歸還是核心功能,因此這部分必須由 API 來處理。
  2. 識別核心資源: 核心資源是 API 必須管理的主要對象,這些資源通常是業務中最重要的實體。在圖書館管理系統中,核心資源可能包括「圖書」、「用戶」和「借閱記錄」。這些資源的管理需要被 API 清晰地界定和實現。
  3. 劃分功能責任: 明確哪些功能應該由 API 來處理,哪些應該留給其他系統或模組來完成。例如,圖書館的書籍管理和借閱系統可以由 API 處理,但身份驗證和支付功能可能應該交給專門的第三方服務來負責。這種劃分可以讓 API 聚焦於核心業務,同時保持整個系統的靈活性和可擴展性。
  4. 正確的HTTP 規格:
    正確使用 HTTP 方法和狀態碼是界定 API 邊界的重要部分。遵循 RESTful 設計原則,我們可以更清晰地定義 API 的功能和行為:
    同時,使用適當的 HTTP 狀態碼可以更好地表達 API 的響應:
    通過正確使用 HTTP 方法和狀態碼,我們可以更好地定義 API 的邊界,使其行為更加清晰和可預測。
    • GET: 用於獲取資源,不應該對資源進行修改。例如,獲取圖書信息或借閱記錄。
    • POST: 用於創建新資源。例如,添加新的圖書或創建新的借閱記錄。
    • PUT: 用於更新現有資源。例如,更新圖書信息或修改借閱記錄。
    • DELETE: 用於刪除資源。例如,刪除過期的借閱記錄。
    • PATCH: 用於部分更新資源。例如,更新圖書的部分信息而不是全部。
    • 200 OK: 請求成功。
    • 201 Created: 資源創建成功。
    • 204 No Content: 請求成功,但無返回內容(如刪除操作)。
    • 400 Bad Request: 請求格式錯誤。
    • 404 Not Found: 請求的資源不存在。
    • 500 Internal Server Error: 服務器內部錯誤。

3. 案例分析:圖書館管理系統的 API 邊界

假設你正在設計一個圖書館管理系統的 API,我們可以通過以下方式來界定它的邊界:

  • 應該處理的功能:
    • 圖書管理: API 應該負責圖書的新增、查詢、更新和刪除。這些操作直接關係到圖書館的核心業務——書籍管理。
    • 借閱管理: API 還應該負責處理書籍的借閱和歸還,包括借閱記錄的維護,這是圖書館運作的關鍵部分。
  • 不應該處理的功能:
    • 身份驗證: 這部分應該由專門的身份驗證系統處理,API 只需接收來自身份驗證系統的驗證結果並據此進行操作。
    • 支付處理: 如果涉及到罰款或其它支付項目,應該由第三方支付服務來處理,API 只需與該支付系統進行集成,處理支付結果即可。

這樣的劃分可以幫助 API 專注於圖書館的核心業務,而不會因為捲入過多的非核心功能而變得複雜難維護。


總結:

界定 API 邊界是設計高效且可維護 API 的第一步。通過明確 API 的職責範圍,我們可以確保它專注於核心業務,並且能夠靈活應對未來的需求變更。這種精確的劃分可以避免過度設計和欠缺設計,從而提高整個系統的穩定性和可擴展性。明天,我們將在此基礎上進一步討論如何建立 API 模型,這將為 API 的實際開發奠定堅實的基礎。

留言
avatar-img
ChiYu Code Journey
1會員
12內容數
歡迎來到 ChiYu Code Journey!這裡是我分享技術心得與開發經驗的空間,主要內容涵蓋 C#、.Net、API 開發及雲端等程式主題。偶爾也會分享一些日常生活點滴,像是我與我家可愛的法鬥相處的趣事等。希望在這裡能和大家一起學習、交流,一同踏上這段程式旅程!
ChiYu Code Journey的其他內容
2025/01/23
在前一篇文章中,我們探討了非同步程式設計的基本概念,並介紹了如何使用 Task、Task<T>、async 和 await 來設計非同步操作。然而,非同步程式設計並非總是那麼直截了當。在實際開發中,開發者經常會遇到一些挑戰,這些挑戰主要來自於高併發、多執行緒以及非同步操作的特性。
2025/01/23
在前一篇文章中,我們探討了非同步程式設計的基本概念,並介紹了如何使用 Task、Task<T>、async 和 await 來設計非同步操作。然而,非同步程式設計並非總是那麼直截了當。在實際開發中,開發者經常會遇到一些挑戰,這些挑戰主要來自於高併發、多執行緒以及非同步操作的特性。
2025/01/22
在 C# 中,非同步程式設計是一種有效提升應用性能、併發處理能力的重要技術。今天,我們將詳細介紹 C# 中的非同步核心概念:async、await、Task 和 Task<T>,說明它們的使用方式,並探討一些進階應用。最後,我們會簡單介紹一些非同步程式設計中常見的問題。 什麼是非同步程式設計?
2025/01/22
在 C# 中,非同步程式設計是一種有效提升應用性能、併發處理能力的重要技術。今天,我們將詳細介紹 C# 中的非同步核心概念:async、await、Task 和 Task<T>,說明它們的使用方式,並探討一些進階應用。最後,我們會簡單介紹一些非同步程式設計中常見的問題。 什麼是非同步程式設計?
2025/01/21
這篇文章探討非同步編程的優缺點,並提供在設計非同步系統時需要注意的事項。非同步編程允許程式在等待 I/O 操作完成的同時,繼續執行其他工作,提高響應速度和資源利用率。然而,非同步程式設計也增加了系統複雜性,需要謹慎處理錯誤和確保代碼可讀性。
Thumbnail
2025/01/21
這篇文章探討非同步編程的優缺點,並提供在設計非同步系統時需要注意的事項。非同步編程允許程式在等待 I/O 操作完成的同時,繼續執行其他工作,提高響應速度和資源利用率。然而,非同步程式設計也增加了系統複雜性,需要謹慎處理錯誤和確保代碼可讀性。
Thumbnail
看更多
你可能也想看
Thumbnail
對於害怕風險、擔心賠錢的投資新手,本文介紹債券投資的優勢,說明其風險相對可控、能定期領息的特性,並介紹玉山「小額債」如何以低門檻(1,000美元/澳幣起)提供投資者參與海外債市的機會,強調其低波動、固定收益的友善特點,適合有明確時間目標的資金規劃。
Thumbnail
對於害怕風險、擔心賠錢的投資新手,本文介紹債券投資的優勢,說明其風險相對可控、能定期領息的特性,並介紹玉山「小額債」如何以低門檻(1,000美元/澳幣起)提供投資者參與海外債市的機會,強調其低波動、固定收益的友善特點,適合有明確時間目標的資金規劃。
Thumbnail
本文深入探討債券投資的本質、常見迷思、風險控制方法,並詳細介紹玉山證券「小額債」平臺的特色與優勢,包括低門檻、24hr即時報價、精準篩選等,幫助投資人建立理性、有紀律的債券投資策略,打造穩定的現金流,讓金錢成為財務上的助力。
Thumbnail
本文深入探討債券投資的本質、常見迷思、風險控制方法,並詳細介紹玉山證券「小額債」平臺的特色與優勢,包括低門檻、24hr即時報價、精準篩選等,幫助投資人建立理性、有紀律的債券投資策略,打造穩定的現金流,讓金錢成為財務上的助力。
Thumbnail
自由工作者收入不穩定,適合選擇穩健的小額債做資產配置。玉山證券小額債最低一千美金就能開始,支援 24 小時委託下單與即時報價,並提供多條件篩選找到適合的債券。本文分享我的操作體驗與為何小額債能成為自由工作者的安心配置。
Thumbnail
自由工作者收入不穩定,適合選擇穩健的小額債做資產配置。玉山證券小額債最低一千美金就能開始,支援 24 小時委託下單與即時報價,並提供多條件篩選找到適合的債券。本文分享我的操作體驗與為何小額債能成為自由工作者的安心配置。
Thumbnail
為什麼「小額債券」會成為越來越多人關注的選項? 如果你跟我一樣,經歷過股市大漲的甜、也嚐過劇烈修正的苦, 大概就會慢慢明白一件事—— 投資,不只是追求報酬,更是關於「穩定感」。 很多投資新手一開始進市場,很容易把全部資金都丟進股票, 漲的時候很快樂,跌的時候卻發現自己根本睡不好。 這
Thumbnail
為什麼「小額債券」會成為越來越多人關注的選項? 如果你跟我一樣,經歷過股市大漲的甜、也嚐過劇烈修正的苦, 大概就會慢慢明白一件事—— 投資,不只是追求報酬,更是關於「穩定感」。 很多投資新手一開始進市場,很容易把全部資金都丟進股票, 漲的時候很快樂,跌的時候卻發現自己根本睡不好。 這
Thumbnail
在現代網路與雲端架構中,負載平衡(Load Balancer)、橫向擴展(Scale Out)、以及 API 溝通機制是不可或缺的基礎。本文帶你快速理解負載平衡如何分散流量、系統如何透過擴展應對成長需求,以及 API 在不同服務間扮演的溝通角色。
Thumbnail
在現代網路與雲端架構中,負載平衡(Load Balancer)、橫向擴展(Scale Out)、以及 API 溝通機制是不可或缺的基礎。本文帶你快速理解負載平衡如何分散流量、系統如何透過擴展應對成長需求,以及 API 在不同服務間扮演的溝通角色。
Thumbnail
在產品開發過程中,PM 對技術概念的理解深度可能會影響需求落地精準度 與開發時程可控性,若能掌握一些基本技術用語,不僅能幫助 PM 更好地理解技術限制與實作可能性,更能提升與工程師的溝通效率。
Thumbnail
在產品開發過程中,PM 對技術概念的理解深度可能會影響需求落地精準度 與開發時程可控性,若能掌握一些基本技術用語,不僅能幫助 PM 更好地理解技術限制與實作可能性,更能提升與工程師的溝通效率。
Thumbnail
有效授權是管理者的關鍵能力。本文探討授權的基礎,包括管理系統的完善、適合的授權對象評估、權責一致性及九大授權條件。授權不僅能提高效率、釋放壓力,更能培養人才。文章也解析組織層級設計與八大功能分支,強調建立清晰授權結構的重要性,以避免混亂並促進企業穩定發展。
Thumbnail
有效授權是管理者的關鍵能力。本文探討授權的基礎,包括管理系統的完善、適合的授權對象評估、權責一致性及九大授權條件。授權不僅能提高效率、釋放壓力,更能培養人才。文章也解析組織層級設計與八大功能分支,強調建立清晰授權結構的重要性,以避免混亂並促進企業穩定發展。
Thumbnail
撰寫的API規格書是軟體PM必學技能,能有效提升開發效率並減少溝通誤差。本文分享API規格書從需求收集、設計架構到版本管理。PM不需寫程式,但需理解API邏輯,成為開發與需求方的溝通橋樑,讓專案更順暢、開發團隊更高效!
Thumbnail
撰寫的API規格書是軟體PM必學技能,能有效提升開發效率並減少溝通誤差。本文分享API規格書從需求收集、設計架構到版本管理。PM不需寫程式,但需理解API邏輯,成為開發與需求方的溝通橋樑,讓專案更順暢、開發團隊更高效!
Thumbnail
在軟體工程中,文件管理常被忽視,但對於多方協作至關重要。本文深入探討API文件、YAML格式和UML圖的應用,強調保持文件的版本控制,使用Swagger和Markdown工具提升可讀性與協作效率。此外,我們將討論如何利用PlantUML輕鬆繪製UML圖,以促進開發團隊之間的有效溝通與理解。
Thumbnail
在軟體工程中,文件管理常被忽視,但對於多方協作至關重要。本文深入探討API文件、YAML格式和UML圖的應用,強調保持文件的版本控制,使用Swagger和Markdown工具提升可讀性與協作效率。此外,我們將討論如何利用PlantUML輕鬆繪製UML圖,以促進開發團隊之間的有效溝通與理解。
Thumbnail
這本書大概花了一個禮拜的零碎時間看完,其實收穫很多,很多原則不僅僅適用於微服務,也適用在單體式應用被部署在很多節點上,加上跟過去的經驗比較,更能體會到書中的觀點
Thumbnail
這本書大概花了一個禮拜的零碎時間看完,其實收穫很多,很多原則不僅僅適用於微服務,也適用在單體式應用被部署在很多節點上,加上跟過去的經驗比較,更能體會到書中的觀點
Thumbnail
為了確保產品順利開發完成並上線,產品經理需要擁有自己的一套原則/產品思維,包括需求分類、用戶體驗、問題導向、數據驅動等,才能讓讓產品團隊更有效地執行項目、降地風險,最終交付解決用戶需求且具有競爭力的產品。
Thumbnail
為了確保產品順利開發完成並上線,產品經理需要擁有自己的一套原則/產品思維,包括需求分類、用戶體驗、問題導向、數據驅動等,才能讓讓產品團隊更有效地執行項目、降地風險,最終交付解決用戶需求且具有競爭力的產品。
Thumbnail
本書是一本說明如何做出讓人能夠秒懂資料的書籍。對於資料內容只是稍有提及,主要側重在外觀打造,讓人能夠在一看到簡報或是資料就能夠大略知道內容。從字型、字級、圖表、圖片的元件為基底,說明該如何使用這些元件,才能打造出讓人易懂的效果。
Thumbnail
本書是一本說明如何做出讓人能夠秒懂資料的書籍。對於資料內容只是稍有提及,主要側重在外觀打造,讓人能夠在一看到簡報或是資料就能夠大略知道內容。從字型、字級、圖表、圖片的元件為基底,說明該如何使用這些元件,才能打造出讓人易懂的效果。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News