【最佳實踐】如何設計 RESTful API ?

2023-05-31 12:01:57

良好的 API 設計是一個經常被提及的話題,特別是對於那些試圖完善其 API 策略的團隊來說。一個設計良好的 API 的好處包括:改進開發者體驗、更快速地編寫檔案以及更高效地推廣你的 API。但是,到底什麼才構成了良好 API 設計呢?在這篇部落格文章中,我將詳細介紹幾個為 RESTful APIs 設計最佳實踐。



一個設計良好的 API 的特點

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

易於閱讀和使用: 設計良好的 API 將很容易使用,並且開發人員可以快速記住其資源和相關操作 。

難以誤用: 實現和整合具有良好設計的 API 是一個簡單直接的過程,並且減少編寫錯誤程式碼。它提供了資訊反饋,並且不會對 API 終端使用者強制執行嚴格指南。

完整而簡潔: 完整的 API 將使開發人員能夠針對您公開資料建立全面應用程式。通常情況下,完成需要時間,大多數 API 設計師和開發人員在現有 API 上逐步構建。這是每個擁有 API 工程師或公司必須努力追求的理想狀態。

為了說明下面列出的概念,我將以一個照片分享應用程式為例。該應用程式允許使用者上傳照片,並使用拍攝這些照片的位置和描述與之相關聯情感的標籤來對它們進行特徵化。



集合、資源及其 URL

理解資源和集合

資源是 REST 概念的基礎。一個資源是一個重要到足以被參照本身的物件。一個資源有資料,與其他資源的關係,以及操作它來允許存取和操作相關資訊的方法。一組資源稱為集合,集合和資源內容取決於您的組織和消費者需求。例如,如果您認為市場將受益於獲取有關產品使用者群體的基本資訊,則可以將其公開為集合或資源。統一資源定位符(URL)標識了一個資源線上位置。這個 URL 指向 API 所在位置中資源存在處 。基礎 URL 是此位置的一致部分,在照片共用應用程式中,我們可以通過適當的 URL 存取通過集合和資料庫使用該應用程式使用者資料。

  1. /users: a collection of users
  2. /users/username1: a resource with information about a specific user

更好地描述 URL

基本的 URL 應該整潔、優雅和簡單,這樣開發人員就可以在他們的 Web 應用程式中輕鬆使用它們。一個長而難以閱讀的基本 URL 不僅看起來不好,而且在嘗試重新編碼時也容易出錯。對於一致性,在所有資源和集合上都保持相同數量是很好的做法。將這些名詞自我解釋有助於開發人員瞭解從 URL 描述的資源型別,最終可以使他們在使用 API 時變得更加獨立自主。

回到照片共用應用程式,假設它有一個公共 API,並具有 /users 和 /photos 作為集合,請注意它們都是複數名詞,它們也是自我說明性質並且我們可以推斷出 /users 和 /photos 分別提供關於產品註冊使用者群體和分享照片資訊。
用 HTTP 方法描述資源功能

所有資源都有一組可以對其進行操作的方法,以處理 API 公開的資料。RESTful API 主要由具有明確定義和獨特操作的 HTTP 方法組成,這些方法定義了任何資源或集合的 CRUD 操作。以下是常用的 HTTP 方法列表,它們為 RESTful API 中任何資源或集合定義了 CRUD 操作:

方法 描述
GET 用於檢索資源的表示形式
POST 用於建立新資源和子資源
PUT 用於更新現有資源
PATCH 用於更新現有資源
DELETE 用於刪除現有資源

在 URL中避免使用動詞也是一個好主意。操作 GET、PUT、POST 和 DELETE 已經用於操作由 URL 描述的資源,因此在 URL中使用動詞會使您的資源處理變得混亂。在照片分享應用程式中,以 /users 和 /photos為 終點,API 的終端使用者可以輕鬆直觀地使用上述 RESTful CRUD 操作來處理它們。



響應

提供反饋幫助開發者成功

向開發人員提供良好的反饋,告訴他們如何更好地使用您的產品,這將有助於提高採用率和留存率。每個使用者端請求和伺服器響應都是一條訊息,在理想的 RESTful 生態系統中,這些訊息必須是自描述的。良好的反饋包括對正確實現進行積極驗證,並在不正確實現時提供資訊性錯誤,以幫助使用者偵錯並糾正其使用產品的方式。

對於 API 而言,錯誤是提供 API 上下文資訊的絕佳方式。將您的錯誤與標準 HTTP 程式碼保持一致,不正確、使用者端呼叫應該與 400 型別錯誤相關聯。如果存在任何伺服器端錯誤,則必須與適當的 500 響應相關聯。針對資源使用成功方法應返回 200 型別響應碼。還有很多其他響應程式碼,請參閱此 REST API 教學獲取更多資訊。

總體而言,在使用您的 API 時可能會出現三種可能結果:

  • 使用者端應用程式出現錯誤(使用者端錯誤 - 4xx 響應程式碼)
  • API 出現錯誤(伺服器錯誤 - 5xx 響應程式碼)
  • 使用者端和 API 工作正常(成功 - 2xx 響應程式碼)

在使用 API 過程中,如果終端使用者遇到問題,為其提供支援將有助於改善開發者體驗並防止 API 濫用。對這些錯誤響應進行清晰簡潔的描述,並提供足夠的資訊以便終端使用者開始修復原因。如果您認為需要更多資訊,請提供檔案。


為所有 GET 響應提供範例

一個設計良好的 API 還應該有一種成功呼叫URL時,期望響應型別的範例,這個範例響應可以被簡單、明瞭和快速理解。一個很好的法則是五秒內幫助開發人員準確地理解成功響應會給他們什麼。回到我們的照片分享應用程式,我們定義了 /users和/photos URL/users 集合將以陣列形式提供已註冊該應用程式的所有使用者的使用者名稱和加入日期。

  responses:
  200:
  description: Successfully returned information about users
  schema:
  type: array
  items:
  type: object
  properties:
  username:
  type: "string"
  example: "kesh92"
  created_time:
  type: "dateTime"
  example: "2020-01-12T05:23:19+0000"

請注意每個響應項中描述的資料型別和範例,終端使用者可以從成功的 GET 呼叫中獲得這些資訊。終端使用者將在 JSON 格式下收到以下成功響應:

{
「data」:[
{
「Username」:「example_user1」,
「created_time":「2013-12-23T05:51:14+0000 」
},
{
「username」:「example_user2」,
「created_time":「2015-3-19T17:51:15+0000 」
}
….
]
}

如果終端使用者使用 GET 方法成功呼叫端點,則使用者應該獲得上述資料以及 200 響應程式碼,以驗證正確的使用。同樣,不正確的呼叫應產生適當的 400 或 500 響應程式碼,並提供相關資訊來幫助使用者更好地操作集合。



請求

優雅地處理複雜性

公開的資料可以由許多屬性來描述,這些屬性對於使用您的 API 的最終消費者非常有益。這些屬性描述了基本資源並隔離了可以使用適當方法操縱的特定資訊資產。API 應該努力實現完整性,並提供所有必需的資訊、資料和資源,以幫助開發人員無縫整合它們。但是完成意味著考慮到 API 的常見用例。可能會有許多此類關係和屬性,為每個關係定義資源不是一個好習慣。還應考慮資源公開的資料量。如果您試圖暴露大量資料,則伺服器可能會出現負面影響,尤其是在負載和效能方面。上述情況和關係是設計 API 時重要考慮因素,並可使用適當引數進行處理。您可以將屬性掃描並將響應限制在查詢引數中「?」後面,或者使用路徑引數隔離使用者端正在處理的資料元件中特定部分 。讓我們以我們照片分享應用程式為例子吧!對於開發人員而言,在特定位置和具體標籤下獲取所有共用照片資訊可能很有用處;同時你也想通過每次呼叫 API 返回 10個結果來限制伺服器負載壓力. 如果終端使用者想要查詢帶有 #winter 標籤波士頓市內所有照片,則呼叫如下:

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

請注意,現在複雜性已經被簡化為與查詢引數的簡單關聯。如果您想根據使用者端請求提供有關特定使用者的資訊,則呼叫將是:

GET /users/kesh92

kesh92 是使用者集合中特定使用者的使用者名稱,將返回 kesh92 的位置和加入日期。這些只是您設計引數以實現 API 完成並幫助最終開發人員直觀使用 API 的一些方法。

如果您對特定資源或集合的功能有所顧慮,則將其保留到下一個迭代中。開發和維護 API 是一個持續過程,並等待來自正確使用者的反饋可以在構建強大的 API 方面產生長遠作用,使使用者能夠以創造性方式整合和開發應用程式。



開始進行 API 設計

沒有一種適用於所有組織的 API 設計方法,上述只是推薦方法。為什麼 API 設計如此重要的一個原因是,它可以幫助最終消費者使用您的 API,他們的需求應該成為設計和構建出色 API 的指路明燈。


Eolink 翻譯,原文地址:https://swagger.io/resources/articles/best-practices-in-api-design/