RESTful API 設計最佳實踐

RESTful API 設計最佳實踐

前言

互聯網 + 時代,RESTful API成為越來越重要的客戶端和服務器端交互的形式。 但是,在人類完全能夠理解HTML文檔的情況下,這不適用於需要特定信息的機器。 這就是為什麼每個體面的互聯網公司的Web服務都有一個API,並可能將它用於他們的網站、應用程序、集成和外部服務。 但不幸的是,太多的 API 隱晦不清,難以使用。 本文將提供一些關於設計遵循Web約定的RESTful,超媒體API的實用建議。

使用URL作為ID

API中的每個概念都應該有自己的URL。 URL應該既作為標識符又作為定位器:它是一個東西的標識,它提供了一種獲取有關該事物的信息的方法。

首先,URL使您的響應更容易導航。當表示社交媒體帖子的JSON對象引用某個具有18EA91FB19標識的作者時,您不知道在哪裡可以找到該作者。您需要閱讀API文檔,發現作者的端點並撰寫您的請求。如果ID是URL,您將立即知道將請求發送到何處。這不僅適用於人類,也適用於機器,因為它們無法讀取您的API文檔 - 但它們可以導航URL。

其次,URL不僅是單個系統中的唯一標識符,而且在不同系統中也是唯一的。域名負責處理。這意味著您可以跨多個系統使用數據。這是使鏈接數據非常棒的屬性之一。

確保您的網址(和ID)穩定。酷URI不會改變。如果他們確實需要更改,請確保將舊網址重定向到新網址。沒有人喜歡斷鏈。

您的API端點就是您的網站

您不需要API的子域,例如 api.example.com 或子路徑, 例如example.com/api 。您的端點應該是您網頁的根目錄: example.com 。

這很有用,因為如上所述,URL應該是作為單個資源的定位符的標識符。無論是某人正在尋找HTML版本還是例如資源的JSON表示,他都應該能夠使用相同的URL。這使您的API更易於使用,因為瀏覽您網站的人可以隨時瞭解如何以其他格式訪問相同的資源。

但是,如果URL不會在格式上發生變化,那麼您如何申請正確的URL?這就是HTTP內容協商派上用場的地方。客戶端可以在Accept HTTP標頭中發送有關要接收的內容類型的首選項。 Web瀏覽器的默認標頭是text / HTML,但對於大多數API,諸如application / json之類的機器可讀設置更合適。

但是API版本怎麼樣?我們希望我們的網址不會更改,因此我們不應對不同的API版本使用不同的網址。解決方案同樣是使用HTTP標頭。在請求中使用api-version標頭或特定的Mime類型。

在URL路徑中使用合理的層次結構

擁有合理的URL層次結構不僅對您的網站很重要,對您的API也很重要 - 特別是如果您的API結構類似於您的網站結構。 嘗試提出合理的URL策略,與您的同事討論,並在開發過程的早期完成所有這些。

一些比較簡潔的事情:

  • 從大到小,從通用到特定。
  • 用戶應該能夠刪除URL的最後部分併到達父資源。
  • 讓層次結構反映導航網站的用戶體驗。
  • 儘量保持網址儘可能短。
  • 人類可讀的URL更容易理解和分享,它們非常適合SEO。
  • 酷URI不會改變。 遺漏任何可能發生變化的內容,例如作者,文件擴展名,狀態或主題。

正確使用查詢參數

URI規範告訴我們僅將查詢參數用於非分層數據。

不要使用查詢參數來標識資源; 使用路徑。

  • 壞的實踐: example.com/posts?id=123
  • 好的實踐: example.com/posts/123

將查詢參數用於限制,排序,過濾和其他修飾符等可選項:

  • 好的實踐: example.com/posts?limit=30
  • 好的實踐: example.com/posts/123?show_hidden=true

使用HTTP方法

不是為各種類型的操作設置一堆端點,而是為應用程序中的每個資源使用一個URL。使用HTTP方法區分操作。

  • 壞的實踐:GET example.com/showPost/123
  • 壞的實踐:GET example.com/removePost/123
  • 好的實踐:GET example.com/posts/123
  • 好的實踐:DELETE example.com/posts/123

旨在閱讀內容,創建內容或編輯內容的請求之間存在很大差異。確保正確使用GET,POST,PUT和PATCH HTTP方法。 GET和PUT操作是冪等的,這意味著請求可以重複多次而沒有副作用。這種區別很重要,因為它告訴客戶端是否可以在發生錯誤時再次嘗試。它還有助於緩存,因為只有GET請求可以緩存。

如果要提供表單來刪除或編輯資源,該表單將與資源本身不同,因此需要一個單獨的URL。一個很好的約定是將表單資源嵌套在資源本身下面。這樣,如果用戶想要編輯該資源,則用戶只需添加/編輯該URL。

  • 好的實踐:GET example.com/posts/123/remove
  • 好的實踐:GET example.com/posts/123/edit

使用HTTP狀態代碼

幾乎所有類型的錯誤消息都可以在現有的HTTP狀態代碼中進行分類。 這些不僅對人類有用,尤其對機器有用。 狀態代碼的解析速度遠遠快於正文。 另一個優點是它們是標準化的,因此客戶端庫可能知道狀態代碼代表什麼。 您不必支持每一個,但至少要確保使用以下五個類別:

  • 1xx:信息 - 只是讓你知道
  • 2xx:成功 - 一切都好
  • 3xx:重定向 - 您的內容在其他地方
  • 4xx:客戶端錯誤 - 你做錯了什麼
  • 5xx:服務器錯誤 - 我們做錯了什麼

為JSON添加上下文

假設您使用JSON作為序列化格式,您可以使用@context。 @context對象是一個非常小的想法,可以使您的API更具自我描述性。 @context對象描述了JSON中各種鍵實際代表的內容。 它提供了可以找到定義的鏈接。 確保您的所有ID都是實際鏈接,幷包含您的上下文。 現在你所有的JSON都變成了JSON-LD,它是鏈接數據。 這意味著您的JSON數據現在可以轉換為RDF(Turtle,N3,N-triples等),這意味著它變得更加可重用。 請記住,您使用的鏈接最好解析為一些解釋您的概念所代表的內容的文檔。 找到相關概念的一個很好的起點是 schema.org 。

提供各種序列化選項

在序列化選項中儘可能靈活。 對於許多MVC框架,添加新序列化程序所需的工作量並不是那麼糟糕。 例如,我們為 Ruby on Rails 編寫了一個庫,以序列化為JSON-LD,RDF/XML,N3,N-triples和Turtle。 使用上述HTTP接受標頭來處理內容協商。

標準化索引頁面和分頁功能

您可能需要使用分頁的索引頁面。 怎麼處理? 分頁不是一個微不足道的問題,但幸運的是,你並不是第一個遇到它的人。 不要試圖重新發明輪子並使用已存在的東西,例如W3C活動流集合或Hydra集合。

不需要API密鑰

您的默認API(HTML版)不需要,因此您的JSON API也不需要。 使用速率限制來確保您的服務器不會爆掉。 當然,您仍然可以使用API密鑰或身份驗證來訪問API的特殊部分。

為API文檔指定 doc. 子域

這是一個聰明的小主意:在doc.example.com上提供您的API文檔。 如果用戶想知道你的api如何適用於某個頁面,他只需添加doc。 在他當前的URL前面。 向用戶顯示一個頁面,告訴我們如何在該路徑上使用API。

定義一套標準的返回體數據結構

對於所有的RESTful HTTP請求定義一套標準的返回結構體,前端可以根據這樣的固定格式做標準化的解析,對於系統的可維護性起到很大的幫助。這個結構體裡應該包含返回的具體資源,結果狀態碼和錯誤原因(如果有的話)。對於返回的資源,數據類型也儘量做到統一,比如日期,枚舉類型都返回統一的數據類型避免不同的API對同一種數據有不同的處理方式。資源屬性儘量做到可讀也能大大減少前後端的溝通成本。

RESTful API的版本控制

一個簡單的做法是直接在URL中插入版本號,這樣可以允許多個版本的API同時運行。在已經發布的版本中儘量做到向後兼容,包括URL和參數,對於返回值也是儘量增加新的冗餘參數以兼容不同客戶端不同的升級頻率。等到所有的客戶端升級以後再去除冗餘的過程。

使用您自己的API

最後,也許最重要的是:吃自己的狗糧。 通過使用它作為從該系統訪問信息的唯一方法,使您的API成為一等公民。 API驅動的開發迫使您使API實際運行。 它可以幫助您正確記錄您的API,因為您的同事也需要使用它。 此外,它有助於使您的應用程序更加模塊化,並逐步幫助您實現微服務架構,它具有自己的一系列優勢。

參考文章:

  1. Best practices for RESTful API design
  2. RESTful API 設計最佳實踐


分享到:


相關文章: