使用 OAS(OpenAPI标准)来描述 Web API
無論哪種類型的Web API, 都可能需要給其他開發(fā)者使用. 所以API的開發(fā)者體驗是很重要的. API的開發(fā)者體驗, 簡寫為 API DX (Developer Experience). 它包含很多東西, 例如如何使用API, 文檔, 技術(shù)支持等等, 但是最重要的還是API的設(shè)計. 如果 API 設(shè)計的不好, 那么使用該API構(gòu)建的軟件就需要增加在時間,人力,金錢等方面的投入. 有時候API會被錯用, 甚至帶來毀滅性后果. 最后抱怨該API等用戶越來越多, 慢慢的, 客戶就會停止使用該API.?
?
API的目的是讓人們可以簡單的使用它來達到自己的目的. 目前行業(yè)內(nèi)有很多API風格, 例如: REST, gRPC, GraphQL, SOAP, RPC等等. 但是每個風格都遵循一些基本的設(shè)計原則.?
?
用戶就是上帝, 為用戶設(shè)計API?
和構(gòu)建任何東西一樣, 你需要一個計劃, 你需要在真正做之前來決定你想要的是什么. API 設(shè)計也是一樣的.?
API 并不是用來盲目的暴露一些數(shù)據(jù)或業(yè)務(wù)處理能力. 它就像我們每天使用的任何形式的接口一樣, 例如微波爐的操作按鈕, 是來幫助用戶完成他們的目標的. 所以需要從用戶的視角來決定一個API的設(shè)計目標. 在整個設(shè)計過程中, 必須牢記以用戶的視角去設(shè)計, 如果以開發(fā)者的角度去設(shè)計, 那么問題就大了.?
?
如果以開發(fā)者的視角去設(shè)計的API, 那么通常的后果是開發(fā)出的API會很注重功能實現(xiàn)的過程和原理, 而不是用戶如何能簡單平滑的使用這個API來達到他們的目的. 所以一定要注重用戶的需求, 而不要讓內(nèi)部實現(xiàn)細節(jié), 原理什么的來騷擾用戶. 最后再次強調(diào), 要設(shè)計出讓用戶容易理解和容易使用的API.?
所以 API 就是用戶看到的, 它表示出用戶能使用它做什么. API 的實現(xiàn)細節(jié), 也就是如果完成的該功能的細節(jié), 需要對用戶隱藏.?
?
識別?API?的目標?
記住首先考慮用戶的感受之后, 下面就需要考慮用戶能拿它來做什么了, 也就是識別API的目標.??
識別 API 的目標, 最基本的要對以下方面有深刻, 精準的認識:?
Who, 誰可以使用這個API??
What, 用戶拿這個API能做什么事???
How, 用戶如何做這件事??
What need, 用戶想要做這件事的話還需要什么??
What return, 用戶會得到什么??
?
1.就是指API的用戶, 4,5分別表示輸入輸出.??
?
針對2, 3解釋一下?
通常針對2.What(用戶拿API能做什么)可以導(dǎo)致(分解)多個3.How(多個步驟), 這樣的話每個步驟就是一個API的目標.?
比如說, 用戶想去淘寶買一個商品, 那么怎么買? 首先需要把商品添加到購物車, 然后再結(jié)賬. 那么這個API就應(yīng)該有兩個目標: 添加商品到購物車, 以及 結(jié)賬.?
如果不這樣分解到話, 通常設(shè)計出的API會缺失一些目標.?
?
針對1,?也解釋一下?
首先應(yīng)該識別出不同種類的用戶, 這里的用戶可能是人, 也可能是其他的程序. 通常通過檢查輸入和輸出就可以識別出用戶.?
?
總結(jié)一下就6個方面:?
用戶?
能做什么?
如何做 - 分解步驟?
輸入?
輸出?
目標?
?
避免從開發(fā)者角度設(shè)計API?
這部分包含幾個方面. 包括:?
開發(fā)者所在公司的組織結(jié)構(gòu)(參考康威定律)?
數(shù)據(jù), 例如數(shù)據(jù)使用了開發(fā)者所在公司內(nèi)部的一些專有術(shù)語, 或者干脆把內(nèi)部數(shù)據(jù)庫模型暴露了出來.?
不要暴露實現(xiàn)細節(jié), 避免受到業(yè)務(wù)邏輯實現(xiàn)細節(jié)的影響?
避免受到軟件架構(gòu)的影響, 比如說在開發(fā)者公司內(nèi)部查詢產(chǎn)品名稱和產(chǎn)品價格是兩個API, 那么給用戶使用的API必須整合一下, 不能讓用戶分兩步查詢.?
?
最重要的還是要時刻牢記, 你所設(shè)計的這些東西都是用戶真正需要的嗎??
?
?
下面切入正題:?
使用API描述格式來描述API?
這里我以RESTful風格的API為例. 想要了解使用ASP.NET Core 3.x 構(gòu)建 RESTful API, 這里有一個教程(但是還沒講完)?https://www.bilibili.com/video/av77957694/.?
?
很多人使用Excel或者紙和筆來進行API的設(shè)計工作. 但是如果想要在設(shè)計階段精準描述一個API, 尤其是它的數(shù)據(jù), 那么最好使用一個結(jié)構(gòu)化的工具, 例如API描述格式.??
API描述格式會為API提供一個標準化的描述, 并且它很像代碼. 它的優(yōu)勢主要有:?
有助于在項目團隊中共享設(shè)計?
了解這種格式的人或者工具可以很簡單的理解它.?
?
針對REST而言, OpenAPI Specification(OAS) 就是一個非常流行API描述格式規(guī)范.?
?
OAS?
API描述格式是一種數(shù)據(jù)格式, 它的目標就是描述API.?
而OAS (OpenAPI Specification)是一個與編程語言無關(guān)的REST API描述格式. 它是由 OAI (OpenAPI Initiative) 所提倡的. OAI 是Linux基金會下面的一個組織, 專注于提供與供應(yīng)商無關(guān)的描述格式. 而OAS則是社區(qū)驅(qū)動的一種格式, 任何人都可以做貢獻.?
?
OAS vs Swagger?
OAS 原來叫 Swagger Specification, 2015年11月這個格式被貢獻給了OAI, 并在2016年1月更名為 OpenAPI Specification. Swagger 規(guī)范最后的2.0版本就變成了 OpenAPI 2.0. 目前最新的OAS 應(yīng)該是3.0大版本?
?
YAML?
OAS文檔可以使用YAML或JSON格式, 我使用YAML.?
?
像寫代碼一樣描述API?
OAS文檔就是一個文本文件, 可以納入版本控制系統(tǒng) ,例如 Git等. 所以在設(shè)計迭代的時候很容易進行版本管理和變化追蹤.?
?
編輯器?
OAS有一個在線的專用編輯器:?http://editor.swagger.io/?
左邊是代碼編輯區(qū)域, 右邊是渲染結(jié)果.?
?
但是我更習(xí)慣于本地編輯器, 我使用VSCode, 并安裝 Swagger Viewer 和 openapi-lint 兩個插件.?
共享API描述,?對API進行文檔記錄?
OAS文檔可以用來生成API對引用文檔, 這個引用文檔可以展示出所有可用的資源以及相應(yīng)的操作. 通常我會使用Swagger UI, 它就是上圖右側(cè)的部分.?
?
生成代碼?
使用API描述格式進行描述的API, 其代碼也可以部分生成. 通常是一個代碼骨架.?
?
什么時候使用API描述格式?
肯定是在設(shè)計接口如何表達API目標和概念, 以及數(shù)據(jù)的時候.?
?
使用OAS來描述REST API的資源以及Action?
創(chuàng)建OAS文檔?
建立一個products.yaml文件.??
然后在里面輸入 api 或 open等字符串, 會出現(xiàn)兩個提示選項:?
先選擇下面那個選項, 其結(jié)果是:?
第1行是Open API的版本?
第4行 info 的 version 是指API的版本, 而info這個版本必須使用雙引號括起來, 否則OAS解析器會把它當成數(shù)字, 從而導(dǎo)致文檔驗證失敗(因為它的類型應(yīng)該是字符串).?
第5行 paths, paths屬性應(yīng)該包含該API可用的資源. 這里面使用 {} 僅僅是為了讓文檔驗證通過, 因為我目前還沒有寫什么內(nèi)容. 在YAML里, {} 表示一個空的對象, 而非空的對象則不需要這對大括號.?
?
描述資源?
為了描述products這個資源, 就需要填寫paths屬性:?
這里description屬性不是強制的, 但是它可以用來描述該資源.?
?
描述資源的操作?
OAS文檔里描述的資源肯定包含一些操作, 否則文檔就不合理.?
看代碼:?
我為/products這個資源添加了一個GET Action (get屬性), 然后我對這個get也進行了描述.?
summary相當于是對這個Action的一個概括性描述, 而description則能提供更詳細的描述信息.??
這里description是支持多行文本的, 但是在YAML里面要想支持多行文本, 那么string屬性必須以 | 管道符 開頭.?
注意, 這里第1行 openapi下面的波浪線表示文檔驗證失敗.?
?
在OAS文檔里, 一個操作必須在responses屬性里提供至少一個響應(yīng):?
一個Action可能有多種響應(yīng)結(jié)果, 每種可能的響應(yīng)結(jié)果都要在responses屬性中描述.?
每個響應(yīng)都以狀態(tài)碼進行標識, 并且必須包含一個description屬性.?
注意: 狀態(tài)碼數(shù)字必須用雙引號括起來, 因為它的類型本應(yīng)該是字符串, 而這里的200是一個數(shù)字.?
?
下面我再添加一個POST Action:?
這里還是針對 /products 這個資源, 我就不過多解釋了.?
?
使用OpenAPI?和?JSON Schema?來描述?API?的數(shù)據(jù)?
OAS 依賴于 JSON Schema 標準來對所有的數(shù)據(jù)(查詢參數(shù), body 參數(shù), 響應(yīng)body等)進行描述.?
?
注意, OAS 使用的其實是JSON Schema的一個子集, 并不包含所有的 JSON Schema 特性, 并且還添加了一些 OAS 獨有的特性到這個子集里.?
?
描述查詢參數(shù)?
如果我們的get操作里需要一些查詢參數(shù)(查詢字符串, Query String), 那么可以使用 parameters 這個屬性:
這里 parameters屬性是一個集合或數(shù)組, 每個集合元素使用 - 開頭.?
為了描述一個參數(shù), 至少需要name, in 和 schema 三個屬性. 在本例中, 還包含 required 和 description 兩個可選的屬性.?
in表示參數(shù)的位置, 這里值為query, 表述它是查詢字符串(Query String, 例如 api/products?searchTerm=xxx).??
required 為 false 表示不是必填參數(shù). required是可選的, 如果沒有寫的話, 那么它的值就是false. 但是最好還是寫上required屬性.?
它的數(shù)據(jù)結(jié)構(gòu)使用schema屬性來表示, 這里就是一個簡單的字符串類型. 但是它其實是一個JSON schema, 所以它可以是復(fù)雜的對象類型.?
description屬性也是可選的, 但是最好還是寫上吧, 有個描述更好.?
?
使用JSON Schema來描述數(shù)據(jù)?
假設(shè)一個對象有三個屬性: 編號(string), 名稱(string), 價格(number). 那么使用JSON Schema來描述它就應(yīng)該是這樣的:?
還沒完, 我還必須指出屬性是否是必填的, 然后我再加上一個remark屬性, 它不是必填的:?
JSON Schema 通過 required 這個集合屬性來表示哪些屬性是必填的.?
?
此外, 我還可以在這里添加 description 和 example (示例)屬性:?
此外 JSON Schema 還支持 對象屬性類型:?
JSON Schema 的東西比較多, 具體可以查找一下官方文檔.?
?
描述響應(yīng)?
在OAS文檔里, 操作響應(yīng)返回的body里的數(shù)據(jù)是用content屬性來表示:?
這里需要注意的就是該操作的結(jié)果是產(chǎn)品的數(shù)組, 所以類型是array, 而array 的 items屬性就包含著數(shù)組元素的schema.?
?
描述?body?參數(shù)?
像 POST 這樣的 Action, 它的參數(shù)是在請求的body里面.?
body參數(shù)需要使用 requestBody屬性描述, 看代碼:?
這個 body 參數(shù)的內(nèi)容也是使用 JSON Schema來描述的.?
?
描述路由參數(shù)?
像 api/products/{productId} 這樣的URI里, productId就是一個路由/路徑參數(shù).?
它可以這樣描述:?
這里面name的值必須和 {} 里面的值一樣.?
in 的值為 path, 表示是路徑參數(shù).?
路徑參數(shù)是必填的, 所以 required 為 true. 不然解析器會報錯.?
?
可復(fù)用組件?
OAS允許使用可復(fù)用的組件, 例如 schema, 參數(shù), 響應(yīng)等等, 使用它們的時候添加個引用就行.?
?
假設(shè)針對 /products 這個資源一共有兩個操作: 一個是返回一組產(chǎn)品, 另一個返回單個產(chǎn)品. 這時候返回產(chǎn)品的JSON Schema就可以使用一個可復(fù)用的schema.?
可復(fù)用的組件要放在components區(qū)域, 它是OAS文檔的一個根級屬性. 看例子:?
這里面, 可復(fù)用的schema被定義在schemas屬性里, 每個可重用的schema的名字就是schemas的值, 這里就是product. 它下就包含著可重用的組件: 一個 JSON Schema.?
?
引用定義好的schema?
引用定義好的schema需要使用到JSON引用. JSON引用這個屬性的名字是$ref, 它的值是一個URL. 這個URL可指向本文檔內(nèi)部甚至外部的組件. 這里我只引用文檔內(nèi)部的組件.?
而針對那個 get Action的返回結(jié)果(數(shù)組類型), 需要把JSON引用放在 array 的 items屬性里.?
?
可復(fù)用參數(shù)?
直接看代碼:?
和可復(fù)用schema類似, 可復(fù)用參數(shù)也放在components下面, 它所在的區(qū)域是 parameters. 其引用方式也類似, 就不過多介紹了.?
?
除了在Action級別引用可復(fù)用參數(shù), 在資源這個級別也可以這樣做:?
預(yù)覽?
?
總結(jié)
以上是生活随笔為你收集整理的使用 OAS(OpenAPI标准)来描述 Web API的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的 .NET Core 博客性能优化经
- 下一篇: dotNET Core 中怎样操作AD(