restful api設計指南

Thurs發表於2020-08-24

一、協議

API 與使用者的通訊協議,總是使用 HTTPs 協議。

二、域名

應該儘量將 API 部署在專用域名之下。

https://api.example.com

如果確定 API 很簡單,不會有進一步擴充套件,可以考慮放在主域名下。

https://example.org/api/

三、版本(Versioning)

應該將 API 的版本號放入 URL

https://api.example.com/v1/

另一種做法是,將版本號放在 HTTP 頭資訊中,但不如放入 URL 方便和直觀。 Github 採用這種做法。

四、路徑(Endpoint)

路徑又稱”終點”(endpoint),表示API的具體網址。

RESTful 架構中,每個網址代表一種資源(resource),所以網址中不能有動詞,只能有名詞,而且所用的名詞往往與資料庫的表格名對應。一般來說,資料庫中的表都是同種記錄的”集合”(collection),所以 API 中的名詞也應該使用複數。

舉例來說,有一個 API 提供動物園(zoo)的資訊,還包括各種動物和僱員的資訊,則它的路徑應該設計成下面這樣。

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

五、HTTP動詞

對於資源的具體操作型別,由HTTP動詞表示。

常用的 HTTP 動詞有下面五個(括號裡是對應的 SQL 命令)。

GETSELECT):從伺服器取出資源(一項或多項)。
POSTCREATE):在伺服器新建一個資源。
PUTUPDATE):在伺服器更新資源(客戶端提供改變後的完整資源)。
PATCHUPDATE):在伺服器更新資源(客戶端提供改變的屬性)。
DELETEDELETE):從伺服器刪除資源。

# 還有兩個不常用的HTTP動詞。

HEAD:獲取資源的後設資料。
OPTIONS:獲取資訊,關於資源的哪些屬性是客戶端可以改變的。

下面是一些例子。

GET /zoos:列出所有動物園
POST /zoos:新建一個動物園
GET /zoos/ID:獲取某個指定動物園的資訊
PUT /zoos/ID:更新某個指定動物園的資訊(提供該動物園的全部資訊)
PATCH /zoos/ID:更新某個指定動物園的資訊(提供該動物園的部分資訊)
DELETE /zoos/ID:刪除某個動物園
GET /zoos/ID/animals:列出某個指定動物園的所有動物
DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物

六、過濾資訊(Filtering)

如果記錄數量很多,伺服器不可能都將它們返回給使用者。 API 應該提供引數,過濾返回結果。

下面是一些常見的引數。

?limit=10:指定返回記錄的數量
?offset=10:指定返回記錄的開始位置。
?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。
?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。
?animal_type_id=1:指定篩選條件
# 引數的設計允許存在冗餘,即允許API路徑和URL引數偶爾有重複。比如,
GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。

七、狀態碼(Status Codes
伺服器向使用者返回的狀態碼和提示資訊,常見的有以下一些(方括號中是該狀態碼對應的 HTTP 動詞)。

200 OK - [GET]:伺服器成功返回使用者請求的資料,該操作是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:使用者新建或修改資料成功。
202 Accepted - [*]:表示一個請求已經進入後臺排隊(非同步任務)
204 NO CONTENT - [DELETE]:使用者刪除資料成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:使用者發出的請求有錯誤,伺服器沒有進行新建或修改資料的操作,該操作是冪等的。
401 Unauthorized - [*]:表示使用者沒有許可權(令牌、使用者名稱、密碼錯誤)。
403 Forbidden - [*] 表示使用者得到授權(與401錯誤相對),但是訪問是被禁止的。
404 NOT FOUND - [*]:使用者發出的請求針對的是不存在的記錄,伺服器沒有進行操作,該操作是冪等的。
406 Not Acceptable - [GET]:使用者請求的格式不可得(比如使用者請求JSON格式,但是隻有XML格式)。
410 Gone -[GET]:使用者請求的資源被永久刪除,且不會再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 當建立一個物件時,發生一個驗證錯誤。
500 INTERNAL SERVER ERROR - [*]:伺服器發生錯誤,使用者將無法判斷髮出的請求是否成功。

狀態碼列表

八、錯誤處理(Error handling)

如果狀態碼是4xx,就應該向使用者返回出錯資訊。一般來說,返回的資訊中將error作為鍵名,出錯資訊作為鍵值即可。

{
    error: "Invalid API key"
}

九、返回結果

針對不同操作,伺服器向使用者返回的結果應該符合以下規範。

GET /collection:返回資源物件的列表(陣列)
GET /collection/resource:返回單個資源物件
POST /collection:返回新生成的資源物件
PUT /collection/resource:返回完整的資源物件
PATCH /collection/resource:返回完整的資源物件
DELETE /collection/resource:返回一個空文件

十、Hypermedia API

RESTful API 最好做到 Hypermedia ,即返回結果中提供連結,連向其他 API 方法,使得使用者不查文件,也知道下一步應該做什麼。

比如,當使用者向 api.example.com 的根目錄發出請求,會得到這樣一個文件。

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面程式碼表示,文件中有一個 link 屬性,使用者讀取這個屬性就知道下一步該呼叫什麼 API 了。rel 表示這個 API 與當前網址的關係(collection 關係,並給出該 collection 的網址), href 表示 API 的路徑, title 表示 API 的標題, type 表示返回型別。

Hypermedia API 的設計被稱為 HATEOASGithub API 就是這種設計,訪問 api.github.com 會得到一個所有可用 API 的網址列表。

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

從上面可以看到,如果想獲取當前使用者的資訊,應該去訪問 api.github.com/user ,然後就得到了下面結果。

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面程式碼表示,伺服器給出了提示資訊,以及文件的網址。

十一、其他
(1)API的身份認證應該使用 OAuth 2.0 框架。

(2)伺服器返回的資料格式,應該儘量使用 JSON ,避免使用 XML

本作品採用《CC 協議》,轉載必須註明作者和本文連結
Thurs

相關文章