API 接口設計規範,看這篇就足以了

優秀的設計是產品變得卓越的原因。設計 API 意味着提供有效的接口,可以幫助 API 使用者更好地瞭解、使用和集成,同時幫助人們有效地維護它。每個產品都需要使用手冊,API 也不例外。
在 API 領域,可以將設計視爲服務器和客戶端之間的協議進行建模。API 協議可以幫助內部和外部的利益相關者理解應該做什麼,以及如何更好地協同工作來構建一個出色的 API。

一、API 接口

1. 什麼是 API 接口

應用程序編程接口(Application Programming Interface,API 接口),是應用程序重要的組成部分,就是應用程序對外提供了一個操作數據的入口,這個入口可以是一個函數或類方法,也可以是一個 url 地址或者一個網絡地址。當客戶端調用這個入口,應用程序則會執行對應代碼操作,給客戶端完成相對應的功能。

2.API 接口類型

目前市面上大部分公司開發人員使用的接口實現規範主要有:Restful、RPC。

RPC( Remote Procedure Call ): 翻譯成中文: 遠程過程調用 [遠程服務調用]. 從字面上理解就是訪問 / 調用遠程服務端提供的 api 接口。這種接口一般以服務或者過程式代碼提供。

接口多了, 對應函數名和參數就多了, 前端在請求 api 接口時難找. 容易出現重複的接口

Restful: 翻譯成中文: 資源狀態轉換.(表徵性狀態轉移)

把服務端提供的所有的數據 / 文件都看成資源, 那麼通過 api 接口請求數據的操作,本質上來說就是對資源的操作了.
因此,Restful 中要求,我們把當前接口對外提供哪種資源進行操作,就把資源的名稱寫在 url 地址。

web 開發中操作資源,最常見的最通用的無非就是增刪查改,所以 restful 要求在地址欄中聲明要操作的資源是什麼。然後通過 http 請求動詞來說明對該資源進行哪一種操作。
POST http://www.xxx.com/api/students/ 添加學生數據
GET http://www.xxx.com/api/students/ 獲取所有學生
DELETE http://www.xxx.com/api/students// 刪除 id=pk 的一個學生
PUT http://www.xxx.com/api/students// 修改一個學生的全部信息 [id,name,sex,age,]
PATCH http://www.xxx.com/api/students// 修改一個學生的部分信息 [age]

也就是說,我們僅需要通過 url 地址上的資源名稱結合 HTTP 請求動作,就可以說明當前 api 接口的功能是什麼了。

Restful 是以資源爲主的 api 接口規範,體現在地址上就是資源就是以名詞表達。
RPC 則以動作爲主的 api 接口規範,體現在接口名稱上往往附帶操作數據的動作。

3. 爲什麼要編寫接口文檔

爲了在團隊內部形成共識、防止個人習慣差異引起的混亂,我們都需要找到一種大家都覺得很好的接口實現規範,而且這種規範能夠讓後端寫的接口,用途一目瞭然,減少客戶端和服務端雙方之間的合作成本。
由於接口所包含的內容比較細,在項目中常常需要使用接口文檔。研發人員可以根據接口文檔進行開發、協作,測試人員可以根據接口文檔進行測試,系統也需要參照接口文檔進行維護等。

二、API 接口規範

1. 協議

API 與客戶端用戶的通信協議,推薦使用 HTTPS 協議,同時兼容 HTTP,以確保交互數據的傳輸安全。

2. 域名

應該儘量將 API 部署在專用域名之下。
https://api.xxx.com

如果確定 API 很簡單,不會有進一步擴展,可以考慮放在主域名下。
https://www.xxx.com/api/

3. 版本(Versioning)

推薦將 API 的版本號放入 URL。

https://api.xxx.com/app/v1.0/foo
https://api.xxx.com/app/v1.1/foo
https://api.xxx.com/app/v2.0/foo

另一種做法是,將版本號放在 HTTP 頭信息中,但不如放入 URL 方便和直觀。

版本號規範:
1)採用多版本並存,增量發佈的方式。
2)版本號可以分爲整型和浮點型
整型:大功能版本,如 v1、v2、v3 ...
浮點型:補充功能版本,如 v1.1、v1.2、v2.1、v2.2 ...

關於版本兼容性,小版本變化向下兼容的,只要大版本不變化。
3)對於一個 API 或服務,應在生產中最多保留 3 個最詳細的版本

4. 路徑(Endpoint)

路徑又稱 "終點"(endpoint),表示 API 的具體網址,每個網址代表一種資源(resource)

接口命名應該是一個動賓結構,由動詞 + 名詞組成,採取駝峯式命名規範,例如:

product/v1.0/getProducts    獲取產品
order/v1.1/saveOrder      保存訂單

接口命名常見通用動詞可以參考如下:

lER2wU

5. 基本規範

5.1 請求參數

公共參數是每個接口都要攜帶的參數,描述每個接口的基本信息,用於統計或其他用途,放在 header 或 url 參數中。

Query
url? 後面的參數,存放請求接口的參數數據。

Header
請求頭,存放以下公共參數、APP 端公共參數等,也可以存放一些特殊加密字段。

Body
Body 體,存放請求接口的參數數據。

公共參數:

pzOxNA

一般 token、timestamp、request_id 和 sign 四個參數會在接口中會同時作爲參數傳遞,每個參數都有各自的用途,其中首次獲取 token 需要 app_id、timestamp、request_id、sign,客戶端獲取 token 後不再需要傳遞 app_id。

APP 端請求公共參數

APP 端請求參數除了上述公共參數外,還需要以下額外公共參數:

Eov6y6

過濾參數:

若記錄數量很多,服務器不可能返回全部記錄給用戶。
API 應該提供分頁參數及其它篩選參數,過濾返回結果。

參數示例如下
limit=10:指定返回記錄的數量
offset=10:指定返回記錄的開始位置。
page=2&per_page=100:指定第幾頁,以及每頁的記錄數。
sort_by=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。

注意:

1)上傳 / 下載
上傳 / 下載,參數增加文件 md5,用於完整性校驗(傳輸過程可能丟失數據)。
2)避免精度丟失
縮小單位保存數據,如:錢以分爲單位、距離以米爲單位。

5.2 響應數據

爲了方便給客戶端響應,響應數據會包含三個屬性,狀態碼(code), 信息描述(message), 響應數據(data)。客戶端根據狀態碼及信息描述可快速知道接口,如果狀態碼返回成功,再開始處理數據。
array 類型數據。通過 list 字段,保證 data 的 Object 結構。

返回示例:

{
code: “SUCCESS”, // 返回碼, 詳情後面的【接口返回碼】部分會說
data: {} ,      // 數據
message: “成功” // 存放響應信息提示,顯示給客戶端用戶【須語義化中文提示】
}

分頁類型數據。返回總條數,用於判斷是否可以加載更多。
返回示例:

{
code: “SUCCESS”,
data: {
"list":[]
"total":10
}, // 數據,
message: “成功”
}

響應狀態碼 code 統一使用英文組合字符串,多層分級使用 “.” 分隔,例如:
PARAMETER.ILLEGALL

PARAMETER.ILLEGALL 代表參數錯誤,不推薦使用數字,數字錯誤碼可讀性太差。

注意:
1)返回屬性名命名時,建議使用駝峯命名,首字母小寫。
2)返回屬性值爲空時,嚴格按類型返回默認值。
3)返回金額類型 / 時間日期類型的屬性值,如果僅用來顯示,建議後端返回可以顯示的字符串。
4)返回業務邏輯的狀態碼和對應的文案,建議後端兩者都返回,中間添加 “|” 分隔,例如“SUCCESS | 成功”,SUCCESS 表示接口狀態成功,顯示給客戶表示“成功”。
5)調用方不需要的屬性,不要返回。

5.3 使用 GET/POST 作爲接口請求方式

一般調用接口最常用的兩種方式就是 GET 和 POST。兩者的區別也很明顯,GET 請求會將參數暴露在瀏覽器 URL 中,而且對長度也有限制。爲了更高的安全性,所有接口都採用 POST 方式請求。
另外不推薦使用 rest 的 PUT 和 DELETE,因爲很多瀏覽器不支持,很多框架也不支持。

我們這裏用的的 GET 和 POST 同 RESTFul 中的 GET、POST 是不一樣的。通常使用 GET、POST 的選擇點在於,簡單的用 GET、複雜對象用 POST,並沒有動作的含義,例如我也可以使用 get 來執行添加的動作,如果參數很多,我也可以使用 POST 來執行查詢操作;但在 REST 裏,GET 對應的是查詢一個資源,而 POST 對應的是新增一個資源,意義是決然不同的。理解這一點非常重要。

5.4 返回格式

返回響應數據採用 JSON,不推薦使用 XML,XML 是 W3C 爲了替換 HTML 研發出來的,但是現在很明顯失敗了。
默認情況下要支持 gzip

三、接口安全規範

3.1 安全設計規範

獲取 token 一般會涉及到幾個參數 app_id,app_key,timestamp,request_id,sign。我們通過以上幾個參數來獲取調用系統的憑證。

token 作爲系統調用的唯一憑證,token 可以設置一次有效,也可以設置時效性,這裏推薦設置時效性。如果一次有效的話這個接口的請求頻率可能會很高。token 推薦加到請求頭上,這樣可以跟業務參數完全區分開來。

這裏面主要涉及到 sign 簽名設計規範和 token 生成規範,需要遵守如上規範,能夠保證 API 接口的安全性和冪等性。

3.2 客戶端 IP 白名單

ip 白名單是指將接口的訪問權限對部分 ip 進行開放。這樣就能避免其他 ip 進行訪問,設置 ip 白名單比較麻煩的一點就是當你的客戶端進行遷移後,就需要重新聯繫服務提供者添加新的 ip 白名單。設置 ip 白名單的方式很多,除了傳統的防火牆之外,spring cloud alibaba 提供的組件 sentinel 也支持白名單設置。爲了降低 api 的複雜度,推薦使用防火牆規則進行白名單設置或者在 API 網關層面設置 IP 白名單,比如 shenyu 網關支持 IP 白名單設置。

3.3 單個接口針對 ip 限流

限流是爲了更好的維護系統穩定性。使用 redis 進行接口調用次數統計,ip + 接口地址作爲 key,訪問次數作爲 value,每次請求 value+1,設置過期時長來限制接口的調用頻率。
不過這裏還是推薦在網關層面進行設置,比如 shenyu 網關支持 IP 限流。

3.4 敏感數據加密與脫敏

參數安全:
登錄密碼、支付密碼,需加密後傳輸,建議使用非對稱加密

響應結果:
用戶手機號、用戶郵箱、身份證號、支付賬號、郵寄地址等要進行脫敏,部分數據加 * 號處理。

在接口調用過程中數據通常需要脫敏安全處理,最常用的方式就是加密。加密方式使用安全性比較高的 RSA 非對稱加密。非對稱加密算法有兩個密鑰,這兩個密鑰完全不同但又完全匹配。只有使用匹配的一對公鑰和私鑰,才能完成對明文的加密和解密過程。

四、API 接口冪等性

冪等性是指任意多次請求的執行結果和一次請求的執行結果所產生的影響相同。說的直白一點就是查詢操作無論查詢多少次都不會影響數據本身,因此查詢操作本身就是冪等的。但是新增操作,每執行一次數據庫就會發生變化,所以它是非冪等的。

我們無法保證接口的每一次調用都是有返回結果的,要考慮到出現網絡異常的情況。
舉個例子,訂單創建時,我們需要去減庫存,這時接口發生了超時,調用方進行了重試,這時是否會多扣一次庫存?

對於一些重要的操作需要防止客戶端重複提交的 (如非冪等性重要操作),具體辦法是當請求第一次提交時將 request_id 作爲 key 保存到 redis,相應的返回結果集作爲 value 存儲到 redis,並設置超時時間。當同一個請求第二次訪問時會先檢測 redis 是否存在該 request_id,如果存在則證明重複提交了,接口直接返回不再繼續調用了。

五、API 調用流程

  1. 接口調用方 (客戶端) 向接口提供方 (服務器) 申請接口調用賬號,申請成功後,接口提供方會給接口調用方一個 app_id 和 app_key

  2. 客戶端攜帶參數 app_id、timestamp、request_id、sign 去調用服務器端的 API token,其中 sign = 加密 (app_id + timestamp +request_id+ app_key)

  3. 使用參數 app_id,timestamp,request_id,sign 來獲取 token,token 作爲系統調用的唯一憑證

  4. 客戶端拿着 token 去訪問相應的接口

  5. 如果 token 過期需要獲取刷新 token

sign 的作用是防止參數被篡改,客戶端調用服務端時需要傳遞 sign 參數,服務器響應客戶端時也可以返回一個 sign 用於客戶端校驗返回的值是否被非法篡改了。

六、接口文檔

1、儘量採用自動化接口文檔,可以做到在線測試,同步更新, 推薦使用 swagger、yapi。
2、應包含:接口 BASE 地址、接口版本、接口模塊分類等。
3、每個接口應包含:
接口地址:不包含接口 BASE 地址。
請求方式: GET、POST。
請求參數:數據格式【默認 JSON、可選 form data】、數據類型、是否必填、中文描述。
響應參數:類型、中文描述。

七、總結

關於限流設計、熔斷設計、降級設計,目前主流網關都有相關功能(比如 shenyu 網關),可以不在 API 實現中開發這些功能。

另外推薦把 API 相關日誌存儲到日誌平臺,日誌平臺有利於故障定位和日誌統計分析以及接口監控。
日誌平臺的搭建可以使用的是 ELK 組件,使用 Logstash 進行收集日誌文件,使用 Elasticsearch 引擎進行搜索分析,最終在 Kibana 平臺展示出來。

Reference:

https://www.cnblogs.com/finer/p/12568417.html

https://www.cnblogs.com/xo1990/p/15674570.html

https://www.easemob.com/news/6806

https://www.jianshu.com/p/3f8953f73a79

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Iy0HT6Id1142qDc6dUduPA