
如何快速實現REST API集成以優化業務流程
{
bookId: 1,
name: "The Republic"
},
{
bookId: 2,
name: "Animal Farm"
}
]
或這樣的組合對象:
{
"data": [
{
"bookId": 1,
"name": "The Republic"
},
{
"bookId": 2,
"name": "Animal Farm"
}
],
"totalDocs": 200,
"nextPageId": 3
}
無論您為此選擇哪種方法,建議都是一致的。在獲取對象時以及在創建和更新資源時應該實現相同的行為,通常返回對象的最后一個實例是個好主意。
// Response after successfully calling POST /books
{
"bookId": 3,
"name": "Brave New World"
}
雖然這不會有什么壞處,但是包含一個像“Book successfully created”這樣的通用消息是多余的,因為它是從 HTTP 狀態代碼中隱含的。
最后但并非最不重要的一點是,錯誤代碼在具有標準響應格式時更為重要。
此消息應包含消費者客戶端可用于向最終用戶顯示錯誤的信息,而不是我們應盡可能避免的通用“出現錯誤”警報。這是一個例子:
{
"code": "book/not_found",
"message": "A book with the ID 6 could not be found"
}
同樣,沒有必要在響應內容中包含狀態代碼,但定義一組錯誤代碼(如 book/not_found)很有用,以便消費者將它們映射到不同的字符串并為用戶決定自己的錯誤消息 . 特別是對于開發/暫存環境,將錯誤堆棧也包含到響應中以幫助調試錯誤似乎就足夠了。
但請不要在生產環境中包含這些內容,因為它會產生暴露不可預測信息的安全風險。
一旦我們構建了一個返回項目列表的端點,就應該進行分頁。集合通常會隨著時間的推移而增長,因此始終返回有限且受控數量的元素非常重要。
讓 API 使用者選擇要獲取多少對象是公平的,但預定義一個數字并為其設置最大值始終是個好主意。這樣做的主要原因是返回大量數據將非常耗費時間和帶寬。
要實現分頁,有兩種眾所周知的方法:skip/limit 或 keyset。
第一個選項允許以更用戶友好的方式獲取數據,但通常性能較低,因為數據庫在獲取“底線”記錄時必須掃描許多文檔。
另一方面,我更喜歡的是,鍵集分頁接收一個標識符/id 作為參考,以在不掃描記錄的情況下“剪切”一個集合或表。
按照同樣的思路,API 應該提供過濾器和排序功能,以豐富數據的獲取方式。為了提高性能,數據庫索引成為解決方案的一部分,以通過這些過濾器和排序選項應用的訪問模式最大限度地提高性能。
作為 API 設計的一部分,分頁、過濾和排序的這些屬性被定義為 URL 上的查詢參數。例如,如果我們想要獲得屬于“浪漫”類別的前 10 本書,我們的端點將如下所示:
GET /books?limit=10&category=romance
我們不太可能需要一次完全更新完整的記錄,通常會有敏感或復雜的數據,我們希望避免用戶操作。考慮到這一點,PATCH 請求應該用于對資源執行部分更新,而 PUT 則完全替換現有資源。
兩者都應該使用請求體來傳遞要更新的信息。對于 PATCH 和 PUT 請求的完整對象,僅修改字段。
盡管如此,值得一提的是,沒有什么能阻止我們使用 PUT 進行部分更新,沒有“網絡傳輸限制”可以驗證這一點,這只是一個值得堅持的慣例。
在創建可用的 API 資源和返回哪些數據時,訪問模式是關鍵。當系統增長時,記錄屬性也會在該過程中增長,但并非所有這些屬性始終是客戶端操作所必需的。
正是在這些情況下,提供為同一端點返回減少或完整響應的能力變得有用。如果消費者只需要一些基本字段,簡化響應有助于減少帶寬消耗,并可能降低獲取其他計算字段的復雜性。
實現此功能的一種簡單方法是提供額外的查詢參數以啟用/禁用擴展響應的提供。
GET /books/:id
{
"bookId": 1,
"name": "The Republic"
}
GET /books/:id?extended=true
{
"bookId": 1,
"name": "The Republic"
"tags": ["philosophy", "history", "Greece"],
"author": {
"id": 1,
"name": "Plato"
}
}
單一職責原則側重于保持函數、方法或類的概念,側重于它擅長的狹義行為。當我們考慮一個給定的 API 時,如果它只做一件事并且永不改變,我們就可以說它是一個好的 API。
這有助于消費者更好地理解我們的 API 并使其可預測,從而促進整體集成。最好將我們的可用端點列表擴展到更多,而不是構建試圖同時解決許多問題的非常復雜的端點。
API 的使用者應該能夠理解如何使用可用端點以及對可用端點的期望。這只有在有良好而詳細的文檔的情況下才有可能。
考慮以下幾個方面以提供文檔完善的 API。
要取得成功的另一個重要部分是在系統更改和添加之后始終使文檔保持最新。實現這一目標的最佳方法是使 API 文檔成為開發的基本部分。這方面的兩個著名工具是 Swagger 和 Postman,它們可用于大多數 API 開發框架。
安全性,我們的 API 應該具備的另一個基本屬性。通過在服務器上安裝有效證書來設置 SSL 將確保與消費者的安全通信并防止多種潛在攻擊。
CORS(跨源資源共享)是一種瀏覽器安全功能,可限制從瀏覽器中運行的腳本發起的跨源 HTTP 請求。
如果您的 REST API 的資源接收到非簡單的跨源 HTTP 請求,則需要為消費者啟用 CORS 支持以進行相應操作。
CORS 協議要求瀏覽器向服務器發送預檢請求,并在發送實際請求之前等待服務器的批準(或憑證請求)。
預檢請求作為使用 OPTIONS 方法(以及其他標頭)的 HTTP 請求出現在 API 中。?
因此,為了支持 CORS,REST API 資源需要實現一個 OPTIONS 方法,該方法可以響應 OPTIONS 預檢請求,至少具有 Fetch 標準規定的以下響應標頭:
分配給這些鍵的值將取決于我們希望 API 的開放性和靈活性。我們可以分配特定的方法和已知的來源或使用通配符來開放 CORS 限制。
作為開發演變過程的一部分,端點開始改變并重建。但我們應該盡可能避免突然改變消費者的端點。
將 API 視為向后兼容的資源是一個好主意,新的和更新的端點應該在不影響以前的標準的情況下可用。
這就是 API 版本控制變得有用的地方,客戶端應該能夠選擇要連接的版本。有多種方法可以聲明 API 版本控制:
1. Adding a new header "x-version=v2"
2. Having a query parameter "?apiVersion=2"
3. Making the version part of the URL: "/v2/books/:id"
詳細了解哪種方法更方便,何時正式發布新版本以及何時棄用舊版本當然是要問的有趣問題,但不要過度擴展此項目,分析將是另一篇文章的一部分。
為了提高我們 API 的性能,密切關注很少更改且經常訪問的數據是有益的。對于這種類型的數據,我們可以考慮使用內存或緩存數據庫,從而避免訪問主數據庫。
這種方法的主要挑戰是數據可能會過時,因此還應考慮采用最新版本的過程。
使用緩存數據對于消費者加載配置和信息目錄非常有用,這些配置和目錄不會隨著時間的推移而改變。
使用緩存時,請確保在標頭中包含 Cache-Control 信息。這將幫助用戶有效地使用緩存系統。
我想不出在某些時候不適用于日期的系統的現實。在數據級別,重要的是在客戶端應用程序的日期顯示方式上保持一致。
ISO 8601 是日期和時間相關數據的國際標準格式。日期應為“Z”或 UTC 格式,客戶可以根據該格式為其決定時區,以防在任何情況下需要顯示此類日期。這是一個關于日期應該是什么樣子的例子:
{
"createdAt": "2022-03-08T19:15:08Z"}
我們的 API 可能會在艱難時期出現故障,并且可能需要一些時間才能啟動并運行它。在這種情況下,客戶會希望知道服務不可用,以便他們了解情況并采取相應行動。為了實現這一點,提供一個端點(如 GET /health)來確定 API 是否健康。這個端點可以被其他應用程序調用,例如負載平衡器。我們甚至可以更進一步,通知有關 API 部分的維護期或健康狀況。
允許通過 API 密鑰進行身份驗證為第三方應用程序提供了輕松創建與我們的 API 集成的能力。
這些 API 密鑰應使用自定義 HTTP 標頭(例如 Api-Key 或 X-Api-Key)傳遞。密鑰應該有一個到期日期,并且必須可以撤銷它們,以便出于安全原因使它們失效。
在今天這篇文章中,我與您分享了15個關于API設計的基本技巧,希望這些技巧對您有所幫助,如果您覺得有用的話,請記得點贊,我關注我,并將這篇文章分享給你的開發者朋友,也許能夠幫助到他們。
最后,感謝您的閱讀。
文章轉自微信公眾號@web前端開發