API設計 – 最佳實踐

好的 API 設計是許多團隊在完善其 API 策略時經常討論的主題。如果 API設計 的好,帶來的好處包括:改善開發者體驗、更快的文件編寫速度,以及 API 的更高採用率。但是,究竟什麼構成了一個好的 API設計 呢?在這篇文章中,我將詳細介紹設計 RESTful API 的一些最佳實踐。

好的 API設計 特色

一般來說,一個有效的 API 設計應具有以下特色:

1. 易於閱讀和使用:設計良好的 API 會很容易使用,開發者在經常使用後,能夠快速記住那些 Resource 和相關的 Operation。
2. 不容易被誤用:實現並整合一個設計良好的 API 會是一個簡單直接的過程,而且比較不容易寫出錯誤的程式碼。它會提供有用的回饋資訊,而且不會對 API 使用者強加過於嚴格的規範。
3. 完整且精簡:最後,一個完整的 API 能讓開發者基於你公開的數據,打造功能齊全的應用程式。通常,完整性是隨著時間逐漸實現的,大多數 API 設計師和開發者會在現有 API 的基礎上逐步增強。這是每個擁有 API 的工程師或公司應該努力追求的理想目標。

為了說明這些概念,我會用一個照片分享APP為例。這個APP允許使用者上傳照片,並標記拍攝這些照片的位置和描述其情感的標籤(hashtags)。

Collections、Resource 及它們的 URL

了解 Resource (資源) 和 Collections (集合)

Resource 是 REST 概念中的核心元素。簡單來說,Resource 是一個足夠重要的物件,可以被單獨引用。Resource 包含資料、與其他 Resource 的關聯,以及對它進行操作的方法,讓我們可以存取並處理相關的資訊。一群 Resource 就稱為 Collection。Collection 和 Resource 的內容會依據您的組織需求和使用者需求而有所不同。舉例來說,如果您認為市場會受益於了解您產品用戶的基本資訊,那麼您可以將這些資訊作為 Collection 或 Resource 來公開。

URL 是用來標識 Resource 的線上位置。這個 URL 指向 API 中 Resource 所在的具體位置,而基礎 URL 則是這個位置中一致不變的部分。以照片分享 APP 為例,我們可以通過 Collection 和 Resource 來公開使用該 APP 的用戶數據,並透過相應的 URL 進行存取。

  • /users: 使用者的Collection (集合)
  • /users/username1: 有關特定使用者的 Resource (資源) 資訊

要點一:名詞更適合用來描述 URL

基礎 URL 應該保持有意義、簡潔且簡單,這樣使用您產品的開發者就能輕鬆地在他們的 web 應用程式中使用。如果基礎 URL 又長又難讀,不僅難懂,還容易在變更程式碼時出錯,而名詞通常是最可靠的。雖然Resource 名詞用單數還是複數沒有硬性規定,但建議 Collection 名詞用複數形式。在 Resource 和 Collection 之間保持一致的單複數形式是好的做法。保持這些名詞自我解釋性,有助於開發者從 URL 中理解資源的種類,這最終可以讓他們在使用您的 API 時更加得心應手。

以照片分享 APP 為例,假設它有一個公開的 API,並且 /users/photos 是 Collection。注意它們都是複數名詞,而且它們的意義非常明確,我們可以推測 /users/photos 分別提供關於產品註冊用戶和共享照片的資訊。

要點二:使用 HTTP 方法描述 Resource 的功能

每個 Resource 都有一組可以對其進行操作的 Method,用來處理 API 公開的數據。RESTful API 主要由 HTTP 方法組成,每個方法對 Resource 都有明確且獨特的操作。以下是常用的 HTTP 方法列表,它們定義了在 RESTful API 中針對 Resource 或 Collection 的 CRUD 操作。

Method 描述
GET 用來獲取 Resource 的表示(即取回資料)。
POST 用來建立新的 Resource 或子 Resource。
PUT 用來更新已存在的 Resource。
PATCH 用來部分更新已存在的 Resource。
DELETE 用來刪除已存在的 Resource。

(如果你想了解 PUT 和 PATCH 的區別,可以查看這篇 StackOverflow 的討論。)
將動詞從 URL 中移除也是個好主意。GET、PUT、POST 和 DELETE 這些操作已經用來操作 URL 所描述的 Resource,所以在 URL 中使用動詞而不是名詞,可能會讓操作變得混亂。在照片分享 app 中,使用 /users/photos 作為端點,API 的終端使用者可以輕鬆地利用前面提到的 RESTful CRUD operation 來直觀地使用這些資源。

Response (回應)

要點一:提供回饋,幫助開發者成功

向開發者提供有關他們如何使用您的產品的良好回饋,對提高採用率和留存率有很大幫助。每個客戶端 Request (請求) 和伺服器端 Response (回應) 都是一條訊息,在理想的 RESTful 生態系統中,這些訊息必須具有自我描述性。良好的回饋包括正確實施時的正面確認,以及在錯誤實施時提供具體的錯誤訊息,幫助使用者進行除錯並修正他們的使用方式。對於 API 來說,錯誤是提供使用上下文的絕佳方式。請將錯誤與標準的 HTTP 狀態碼對齊。當用戶端的 Request 不正確時,應返回 400 類型的錯誤。如果有伺服器端的錯誤,則必須返回合適的 500 類型回應。而針對資源的成功操作應返回 200 類型的回應。回應碼有很多,想了解更多資訊,可以參考這篇 REST API 教程

一般來說,使用 API 會有三種可能的結果:

1. 用戶端應用程式出現錯誤(Client 端錯誤 – 4xx 回應碼)
2. API 本身出現錯誤(Server 端錯誤 – 5xx 回應碼)
用戶端和 API 工作正常(成功 – 2xx 回應碼)

當終端使用者在使用您的 API 時遇到障礙,幫助他們走向成功,這將大大改善開發者體驗,並防止 API 被誤用。要好好描述這些錯誤 Response,但要保持簡潔和整潔。在錯誤碼中提供足夠的資訊,讓終端使用者能夠開始修正問題的根源,如果您認為需要更多資訊,則可以提供指向其他文件的連結。

要點二:為所有的 GET Response 提供範例

設計良好的 API 也應該提供一個成功呼叫 URL 後的 Response 範例。這個 Response 範例應該簡單明瞭,易於理解。遵循一個簡單的原則:幫助開發者在五秒內清楚理解成功 Response 會提供什麼內容。回到我們的照片分享 APP,我們已經定義了 /users/photos 的 URL。/users Collection 將以陣列的形式返回所有註冊用戶的用戶名和註冊日期。您可以使用 API設計 工具按照 Swagger(OpenAPI)規範來定義 API,如下所示:

responses:
  200:
    description: 成功返回有關使用者的信息
    schema:
      type: array
      items:
        type: object
        properties:
          username:
            type: "string"
            example: "jonathan"
          created_time:
            type: "dateTime"
            example: "2024-01-12T05:23:19+0000"

請注意,每個 Response 項目中描述的數據類型和範例,這些是終端使用者在成功的呼叫 GET 後可以預期的內容。成功的 Response 將以 JSON 的形式返回,內容如下:

{
  “data”:[
    {
      “Username”:“example_user1”,
      “created_time":“2017-12-23T05:51:14+0000 ”
    },
    {
      “username”:“example_user2”,
      “created_time":“2019-3-19T17:51:15+0000 ”
    }
    ….
  ]
}

如果終端使用者成功使用 GET Method 呼叫該端點,用戶應該會獲得上述內容,並伴隨 200 回應碼來驗證正確的使用。同樣地,不正確的呼叫應該產生相應的 400 或 500 回應碼,並提供相關信息,幫助使用者更好地使用這個 Collection。

Request (請求)

要點一:輕鬆的處理複雜的東西

您想公開的數據可能包含許多屬性,這些屬性對使用您的 API 的終端使用者來說非常有幫助。這些屬性描述了基本的 Resource,並且將特定的資訊部分隔離出來,這些資訊可以通過適當的 Method 進行操作。API 應該朝著完整性努力,提供所有必要的資訊、數據和 Resource,幫助開發者無縫整合。但完整性意味著需要考慮常見的 API 使用場景。這樣的關聯和屬性可能有很多,但為每一個都定義 Resource 並不是好的做法。還需要考慮 Resource 暴露的數據量。如果公開太多數據,可能會對伺服器產生負面影響,特別是在負載和效能方面。以上情況和關聯是設計 API 時的重要考量點,這些可以通過適當的參數來處理。您可以使用查詢參數(在 ‘?’ 後面)來過濾屬性並限制 Response,或者使用路徑參數來隔離客戶端正在處理的特定數據部分。

以我們的照片分享 APP 為例,開發者可能需要獲取特定位置和特定標籤的所有照片信息。您還希望每次 API 呼叫的結果限制在 10 筆,以減輕伺服器負擔。如果終端使用者想找到台北市所有帶有 #winter 標籤的照片,Request 應該是:

GET /photos?location=taipei&hashtag=winter&limit=10

您可以發現,複雜性現在已被簡化為與查詢參數的簡單關聯。如果您想根據客戶端的 Request 提供特定使用者的資訊,Request 應該是:

GET /users/jonathan

其中,jonathan 是 users Collection 中的一個具體使用者名稱,會返回 jonathan 的位置和註冊日期。這些只是設計參數的一些方法,這些參數旨在實現 API 的完整性,並幫助開發者更直觀地使用 API。

最後,如果有無法確定的地方,寧願先不要處理。如果您對某個 Resource 或 Collection 的功能有不同的想法,則可以留到下一次迭代。開發和維護 API 是一個持續的過程,等待正確使用者的反饋有助於設計與開發一個健全的 API,讓使用者能夠以創造性的方式整合並開發應用程式。

開始 API 設計
沒有一種方法適合每個組織的 API 設計。上述建議僅是一些建議,您可以根據實際的使用情境和需求選擇採納或忽略。API 設計之所以關鍵,其中一個主要原因是幫助終端使用者正確地使用您的 API。他們的需求應該是我們設計和建立優良 API 的重要依據。

當然,您也可以搭配使用 SwaggerHub,並運用新版 SwaggerHub 表單編輯器,讓 API設計 變的更簡單方便,趕快開始試用吧!


文章來源: Best Practices in API Design, SmartBear 2024