無論哪種類型的Web API, 都可能需要給其他開發者使用. 是以API的開發者體驗是很重要的. API的開發者體驗, 簡寫為 API DX (Developer Experience). 它包含很多東西, 例如如何使用API, 文檔, 技術支援等等, 但是最重要的還是API的設計. 如果 API 設計的不好, 那麼使用該API建構的軟體就需要增加在時間,人力,金錢等方面的投入. 有時候API會被錯用, 甚至帶來毀滅性後果. 最後抱怨該API等使用者越來越多, 慢慢的, 客戶就會停止使用該API.
API的目的是讓人們可以簡單的使用它來達到自己的目的. 目前行業内有很多API風格, 例如: REST, gRPC, GraphQL, SOAP, RPC等等. 但是每個風格都遵循一些基本的設計原則.
和建構任何東西一樣, 你需要一個計劃, 你需要在真正做之前來決定你想要的是什麼. API 設計也是一樣的.
API 并不是用來盲目的暴露一些資料或業務處理能力. 它就像我們每天使用的任何形式的接口一樣, 例如微波爐的操作按鈕, 是來幫助使用者完成他們的目标的. 是以需要從使用者的視角來決定一個API的設計目标. 在整個設計過程中, 必須牢記以使用者的視角去設計, 如果以開發者的角度去設計, 那麼問題就大了.
如果以開發者的視角去設計的API, 那麼通常的後果是開發出的API會很注重功能實作的過程和原理, 而不是使用者如何能簡單平滑的使用這個API來達到他們的目的. 是以一定要注重使用者的需求, 而不要讓内部實作細節, 原理什麼的來騷擾使用者. 最後再次強調, 要設計出讓使用者容易了解和容易使用的API.
是以 API 就是使用者看到的, 它表示出使用者能使用它做什麼. API 的實作細節, 也就是如果完成的該功能的細節, 需要對使用者隐藏.
記住首先考慮使用者的感受之後, 下面就需要考慮使用者能拿它來做什麼了, 也就是識别API的目标.
識别 API 的目标, 最基本的要對以下方面有深刻, 精準的認識:
Who, 誰可以使用這個API?
What, 使用者拿這個API能做什麼事?
How, 使用者如何做這件事?
What need, 使用者想要做這件事的話還需要什麼?
What return, 使用者會得到什麼?
1.就是指API的使用者, 4,5分别表示輸入輸出.
通常針對2.What(使用者拿API能做什麼)可以導緻(分解)多個3.How(多個步驟), 這樣的話每個步驟就是一個API的目标.
比如說, 使用者想去淘寶買一個商品, 那麼怎麼買? 首先需要把商品添加到購物車, 然後再結賬. 那麼這個API就應該有兩個目标: 添加商品到購物車, 以及 結賬.
如果不這樣分解到話, 通常設計出的API會缺失一些目标.
首先應該識别出不同種類的使用者, 這裡的使用者可能是人, 也可能是其他的程式. 通常通過檢查輸入和輸出就可以識别出使用者.
總結一下就6個方面:
使用者
能做什麼
如何做 - 分解步驟
輸入
輸出
目标
這部分包含幾個方面. 包括:
開發者所在公司的組織結構(參考康威定律)
資料, 例如資料使用了開發者所在公司内部的一些專有術語, 或者幹脆把内部資料庫模型暴露了出來.
不要暴露實作細節, 避免受到業務邏輯實作細節的影響
避免受到軟體架構的影響, 比如說在開發者公司内部查詢産品名稱和産品價格是兩個API, 那麼給使用者使用的API必須整合一下, 不能讓使用者分兩步查詢.
最重要的還是要時刻牢記, 你所設計的這些東西都是使用者真正需要的嗎?
下面切入正題:
這裡我以RESTful風格的API為例. 想要了解使用ASP.NET Core 3.x 建構 RESTful API, 這裡有一個教程(但是還沒講完) https://www.bilibili.com/video/av77957694/.
很多人使用Excel或者紙和筆來進行API的設計工作. 但是如果想要在設計階段精準描述一個API, 尤其是它的資料, 那麼最好使用一個結構化的工具, 例如API描述格式.
API描述格式會為API提供一個标準化的描述, 并且它很像代碼. 它的優勢主要有:
有助于在項目團隊中共享設計
了解這種格式的人或者工具可以很簡單的了解它.
針對REST而言, OpenAPI Specification(OAS) 就是一個非常流行API描述格式規範.
API描述格式是一種資料格式, 它的目标就是描述API.
而OAS (OpenAPI Specification)是一個與程式設計語言無關的REST API描述格式. 它是由 OAI (OpenAPI Initiative) 所提倡的. OAI 是Linux基金會下面的一個組織, 專注于提供與供應商無關的描述格式. 而OAS則是社群驅動的一種格式, 任何人都可以做貢獻.
OAS 原來叫 Swagger Specification, 2015年11月這個格式被貢獻給了OAI, 并在2016年1月更名為 OpenAPI Specification. Swagger 規範最後的2.0版本就變成了 OpenAPI 2.0. 目前最新的OAS 應該是3.0大版本
OAS文檔可以使用YAML或JSON格式, 我使用YAML.
OAS文檔就是一個文本檔案, 可以納入版本控制系統 ,例如 Git等. 是以在設計疊代的時候很容易進行版本管理和變化追蹤.
OAS有一個線上的專用編輯器: http://editor.swagger.io/
左邊是代碼編輯區域, 右邊是渲染結果.
但是我更習慣于本地編輯器, 我使用VSCode, 并安裝 Swagger Viewer 和 openapi-lint 兩個插件.
OAS文檔可以用來生成API對引用文檔, 這個引用文檔可以展示出所有可用的資源以及相應的操作. 通常我會使用Swagger UI, 它就是上圖右側的部分.
使用API描述格式進行描述的API, 其代碼也可以部分生成. 通常是一個代碼骨架.
肯定是在設計接口如何表達API目标和概念, 以及資料的時候.
建立一個products.yaml檔案.
然後在裡面輸入 api 或 open等字元串, 會出現兩個提示選項:
先選擇下面那個選項, 其結果是:
第1行是Open API的版本
第4行 info 的 version 是指API的版本, 而info這個版本必須使用雙引号括起來, 否則OAS解析器會把它當成數字, 進而導緻文檔驗證失敗(因為它的類型應該是字元串).
第5行 paths, paths屬性應該包含該API可用的資源. 這裡面使用 {} 僅僅是為了讓文檔驗證通過, 因為我目前還沒有寫什麼内容. 在YAML裡, {} 表示一個空的對象, 而非空的對象則不需要這對大括号.
為了描述products這個資源, 就需要填寫paths屬性:
這裡description屬性不是強制的, 但是它可以用來描述該資源.
OAS文檔裡描述的資源肯定包含一些操作, 否則文檔就不合理.
看代碼:
我為/products這個資源添加了一個GET Action (get屬性), 然後我對這個get也進行了描述.
summary相當于是對這個Action的一個概括性描述, 而description則能提供更詳細的描述資訊.
這裡description是支援多行文本的, 但是在YAML裡面要想支援多行文本, 那麼string屬性必須以 | 管道符 開頭.
注意, 這裡第1行 openapi下面的波浪線表示文檔驗證失敗.
在OAS文檔裡, 一個操作必須在responses屬性裡提供至少一個響應:
一個Action可能有多種響應結果, 每種可能的響應結果都要在responses屬性中描述.
每個響應都以狀态碼進行辨別, 并且必須包含一個description屬性.
注意: 狀态碼數字必須用雙引号括起來, 因為它的類型本應該是字元串, 而這裡的200是一個數字.
下面我再添加一個POST Action:
這裡還是針對 /products 這個資源, 我就不過多解釋了.
OAS 依賴于 JSON Schema 标準來對所有的資料(查詢參數, body 參數, 響應body等)進行描述.
注意, OAS 使用的其實是JSON Schema的一個子集, 并不包含所有的 JSON Schema 特性, 并且還添加了一些 OAS 獨有的特性到這個子集裡.
如果我們的get操作裡需要一些查詢參數(查詢字元串, Query String), 那麼可以使用 parameters 這個屬性:

這裡 parameters屬性是一個集合或數組, 每個集合元素使用 - 開頭.
為了描述一個參數, 至少需要name, in 和 schema 三個屬性. 在本例中, 還包含 required 和 description 兩個可選的屬性.
in表示參數的位置, 這裡值為query, 表述它是查詢字元串(Query String, 例如 api/products?searchTerm=xxx).
required 為 false 表示不是必填參數. required是可選的, 如果沒有寫的話, 那麼它的值就是false. 但是最好還是寫上required屬性.
它的資料結構使用schema屬性來表示, 這裡就是一個簡單的字元串類型. 但是它其實是一個JSON schema, 是以它可以是複雜的對象類型.
description屬性也是可選的, 但是最好還是寫上吧, 有個描述更好.
假設一個對象有三個屬性: 編号(string), 名稱(string), 價格(number). 那麼使用JSON Schema來描述它就應該是這樣的:
還沒完, 我還必須指出屬性是否是必填的, 然後我再加上一個remark屬性, 它不是必填的:
JSON Schema 通過 required 這個集合屬性來表示哪些屬性是必填的.
此外, 我還可以在這裡添加 description 和 example (示例)屬性:
此外 JSON Schema 還支援 對象屬性類型:
JSON Schema 的東西比較多, 具體可以查找一下官方文檔.
在OAS文檔裡, 操作響應傳回的body裡的資料是用content屬性來表示:
這裡需要注意的就是該操作的結果是産品的數組, 是以類型是array, 而array 的 items屬性就包含着數組元素的schema.
像 POST 這樣的 Action, 它的參數是在請求的body裡面.
body參數需要使用 requestBody屬性描述, 看代碼:
這個 body 參數的内容也是使用 JSON Schema來描述的.
像 api/products/{productId} 這樣的URI裡, productId就是一個路由/路徑參數.
它可以這樣描述:
這裡面name的值必須和 {} 裡面的值一樣.
in 的值為 path, 表示是路徑參數.
路徑參數是必填的, 是以 required 為 true. 不然解析器會報錯.
OAS允許使用可複用的元件, 例如 schema, 參數, 響應等等, 使用它們的時候添加個引用就行.
假設針對 /products 這個資源一共有兩個操作: 一個是傳回一組産品, 另一個傳回單個産品. 這時候傳回産品的JSON Schema就可以使用一個可複用的schema.
可複用的元件要放在components區域, 它是OAS文檔的一個根級屬性. 看例子:
這裡面, 可複用的schema被定義在schemas屬性裡, 每個可重用的schema的名字就是schemas的值, 這裡就是product. 它下就包含着可重用的元件: 一個 JSON Schema.
引用定義好的schema需要使用到JSON引用. JSON引用這個屬性的名字是$ref, 它的值是一個URL. 這個URL可指向本文檔内部甚至外部的元件. 這裡我隻引用文檔内部的元件.
而針對那個 get Action的傳回結果(數組類型), 需要把JSON引用放在 array 的 items屬性裡.
直接看代碼:
和可複用schema類似, 可複用參數也放在components下面, 它所在的區域是 parameters. 其引用方式也類似, 就不過多介紹了.
除了在Action級别引用可複用參數, 在資源這個級别也可以這樣做: