使用 OAS(OpenAPI標準)來描述 Web API

不管哪一種類型的Web API, 均可能須要給其餘開發者使用. 因此API的開發者體驗是很重要的. API的開發者體驗, 簡寫爲 API DX (Developer Experience). 它包含不少東西, 例如如何使用API, 文檔, 技術支持等等, 可是最重要的仍是API的設計. 若是 API 設計的很差, 那麼使用該API構建的軟件就須要增長在時間,人力,金錢等方面的投入. 有時候API會被錯用, 甚至帶來毀滅性後果. 最後抱怨該API等用戶愈來愈多, 慢慢的, 客戶就會中止使用該API. html

 

API的目的是讓人們能夠簡單的使用它來達到本身的目的. 目前行業內有不少API風格, 例如: REST, gRPC, GraphQL, SOAP, RPC等等. 可是每一個風格都遵循一些基本的設計原則. node

 

用戶就是上帝, 爲用戶設計API 

和構建任何東西同樣, 你須要一個計劃, 你須要在真正作以前來決定你想要的是什麼. API 設計也是同樣的. 數據庫

API 並非用來盲目的暴露一些數據或業務處理能力. 它就像咱們天天使用的任何形式的接口同樣, 例如微波爐的操做按鈕, 是來幫助用戶完成他們的目標的. 因此須要從用戶的視角來決定一個API的設計目標. 在整個設計過程當中, 必須牢記以用戶的視角去設計, 若是以開發者的角度去設計, 那麼問題就大了. apache

 

若是以開發者的視角去設計的API, 那麼一般的後果是開發出的API會很注重功能實現的過程和原理, 而不是用戶如何能簡單平滑的使用這個API來達到他們的目的. 因此必定要注重用戶的需求, 而不要讓內部實現細節, 原理什麼的來騷擾用戶. 最後再次強調, 要設計出讓用戶容易理解和容易使用的API. 編程

因此 API 就是用戶看到的, 它表示出用戶能使用它作什麼. API 的實現細節, 也就是若是完成的該功能的細節, 須要對用戶隱藏. json

 

識別 API 的目標 

記住首先考慮用戶的感覺以後, 下面就須要考慮用戶能拿它來作什麼了, 也就是識別API的目標.  api

識別 API 的目標, 最基本的要對如下方面有深入, 精準的認識: 數組

  1. Who, 誰可使用這個API? 數據結構

  2. What, 用戶拿這個API能作什麼事?  架構

  3. How, 用戶如何作這件事? 

  4. What need, 用戶想要作這件事的話還須要什麼? 

  5. What return, 用戶會獲得什麼? 

 

1.就是指API的用戶, 4,5分別表示輸入輸出.  

 

針對2, 3解釋一下 

一般針對2.What(用戶拿API能作什麼)能夠致使(分解)多個3.How(多個步驟), 這樣的話每一個步驟就是一個API的目標. 

好比說, 用戶想去淘寶買一個商品, 那麼怎麼買? 首先須要把商品添加到購物車, 而後再結帳. 那麼這個API就應該有兩個目標: 添加商品到購物車, 以及 結帳. 

若是不這樣分解到話, 一般設計出的API會缺失一些目標. 

 

針對1, 也解釋一下 

首先應該識別出不一樣種類的用戶, 這裏的用戶多是人, 也多是其餘的程序. 一般經過檢查輸入和輸出就能夠識別出用戶. 

 

總結一下就6個方面: 

  • 用戶 

  • 能作什麼 

  • 如何作 - 分解步驟 

  • 輸入 

  • 輸出 

  • 目標 

 

避免從開發者角度設計API 

這部分包含幾個方面. 包括: 

  • 開發者所在公司的組織結構(參考康威定律) 

  • 數據, 例如數據使用了開發者所在公司內部的一些專有術語, 或者乾脆把內部數據庫模型暴露了出來. 

  • 不要暴露實現細節, 避免受到業務邏輯實現細節的影響 

  • 避免受到軟件架構的影響, 好比說在開發者公司內部查詢產品名稱和產品價格是兩個API, 那麼給用戶使用的API必須整合一下, 不能讓用戶分兩步查詢. 

 

最重要的仍是要時刻牢記, 你所設計的這些東西都是用戶真正須要的嗎? 

 

 

下面切入正題: 

使用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描述格式規範. 

 

OAS 

API描述格式是一種數據格式, 它的目標就是描述API. 

而OAS (OpenAPI Specification)是一個與編程語言無關的REST API描述格式. 它是由 OAI (OpenAPI Initiative) 所提倡的. OAI 是Linux基金會下面的一個組織, 專一於提供與供應商無關的描述格式. 而OAS則是社區驅動的一種格式, 任何人均可以作貢獻. 

 

OAS vs Swagger 

OAS 原來叫 Swagger Specification, 2015年11月這個格式被貢獻給了OAI, 並在2016年1月改名爲 OpenAPI Specification. Swagger 規範最後的2.0版本就變成了 OpenAPI 2.0. 目前最新的OAS 應該是3.0大版本 

 

YAML 

OAS文檔可使用YAML或JSON格式, 我使用YAML. 

 

像寫代碼同樣描述API 

OAS文檔就是一個文本文件, 能夠歸入版本控制系統 ,例如 Git等. 因此在設計迭代的時候很容易進行版本管理和變化追蹤. 

 

編輯器 

OAS有一個在線的專用編輯器: http://editor.swagger.io/ 

@Swagger Ed 
itor. 
File , 
Edit 
Generate Server 
Generate Client 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
16 
17 - 
18 
19 
21 
23 
24 
25 
26 
27 
28 
29 
30 
SMARTBEAR 
Swagger: 
"2.0" 
info: 
description: 
more about 
"This is a sample server Petstore server. You can find out 
Swagger at Chttp://swagger.io](http://swagger.io) or on 
Circ. freenode.net, #swagger](http://swagger.io/irc/). 
For this 
sample, you can use the api key •special-key' 
fi Iters . " 
version: 
"1.0.0" 
title: "Swagger Petstore" 
terms0fService : 
"http : //swagger. io/terms/" 
to test the authorization 
1.0.0 
Swagger Petstore 
[ Base URL: petstore . swagger. io/v2 J 
This is a sample server Petstore server. You can find out more about Swagger at bttp://swagger.io or on 
irc.freenode.net, #swagger. For this sample, you can use the api key special—key to test the 
contact: 
emai I : 
" apitean@swagger.10 
license: 
name: "Apache 2.0" 
url: 
host: "petstore . swagger. io" 
basePath: "/v2" 
tags : 
"pet" 
15- - name: 
" http : //www.apache.org/licenses/LICENSE-2. O. html " 
description: "Everything about your Pets" 
external Docs: 
description: "Find out more" 
"http : //swagger. io" 
url: 
20- - name: "store" 
description: "Access to Petstore orders" 
22 • - name: "user" 
description: "Operations about user" 
external Docs: 
description: "Find out more about our 
url: 
"http : //swagger. to" 
schemes : 
"https" 
"http" 
naths: 
authorization filters. 
Terms of service 
Contact the developer 
Apache 2.0 
Find out more about Swagger 
Schemes 
HTTPS 
pet Everything about your Pets 
Authorize 
Find out more: http://swagger.io 
store" 
POST 
PUT 
/ pet 
/pet 
Add a new pet to the store 
Update an existing pet

左邊是代碼編輯區域, 右邊是渲染結果. 

 

可是我更習慣於本地編輯器, 我使用VSCode, 並安裝 Swagger Viewer 和 openapi-lint 兩個插件. 

EXPLORER 
v OPEN EDITORS 
GROUP 1 
{O one.yaml 
GROUP 2 
x Swagger Preview 
v OAS 
{n} one.yaml 
{O product.yaml 
{n} one.yaml X 
{O one.yaml > { } paths > (products > { } 
Swagger Preview - /Users/solenovex/OAS/one.yaml 
post > { } 
responses > { } 
or 
200 > 
- /Users/solenovex/OAS... 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
openapi: 3. ø.ø 
info: 
title: "Shopping API" 
version 
: "l.ø.ø•• 
paths: 
/products: 
description: The products catalog 
get: 
summary: Sea rch for products 
description: I 
Search for products in catalog 
using a free query parameter 
parameters: 
— name: free—query 
description: I 
A product 's name, reference, 
partial description 
in: query 
required: false 
schema : 
type: string 
responses: 
description: I 
desc 
Swagger 
SMARTBEAR 
Shopping API 
default 
I.o.o 
OAS3 
GET 
POST 
/products Search for products 
/ products Add P roduct 
Products matching free query parameter 
content: 
application/json: 
schema : 
type: array 
description: Array of products 
items : 
type: object 
description: A product 
required: 
reference 
— name

 

共享API描述API進行文檔記錄 

OAS文檔能夠用來生成API對引用文檔, 這個引用文檔能夠展現出全部可用的資源以及相應的操做. 一般我會使用Swagger UI, 它就是上圖右側的部分. 

 

生成代碼 

使用API描述格式進行描述的API, 其代碼也能夠部分生成. 一般是一個代碼骨架. 

 

何時使用API描述格式 

確定是在設計接口如何表達API目標和概念, 以及數據的時候. 

 

使用OAS來描述REST API的資源以及Action 

建立OAS文檔 

創建一個products.yaml文件.  

而後在裏面輸入 api 或 open等字符串, 會出現兩個提示選項: 

products.yaml 
1 
api 
openapi, OpenAPI 3.0 lintable 
openapi, OpenAPI 3.0 minimal 
OpenAPI 3.0 minimal O

 

先選擇下面那個選項, 其結果是: 

products.yaml > { } paths 
1 
2 
3 
4 
5 
openapi: 3.ø.ø 
info: 
title: "API" 
versxon 1 
paths:
  • 第1行是Open API的版本 

  • 第4行 info 的 version 是指API的版本, 而info這個版本必須使用雙引號括起來, 不然OAS解析器會把它當成數字, 從而致使文檔驗證失敗(由於它的類型應該是字符串). 

  • 第5行 paths, paths屬性應該包含該API可用的資源. 這裏面使用 {} 僅僅是爲了讓文檔驗證經過, 由於我目前尚未寫什麼內容. 在YAML裏, {} 表示一個空的對象, 而非空的對象則不須要這對大括號. 

 

描述資源 

爲了描述products這個資源, 就須要填寫paths屬性: 

1 
2 
3 
4 
5 
6 
7 
openapi: 3.ø.ø 
info: 
title: "API" 
version 
paths: 
/products: 
description: FR51J*l

這裏description屬性不是強制的, 可是它能夠用來描述該資源. 

 

描述資源的操做 

OAS文檔裏描述的資源確定包含一些操做, 不然文檔就不合理. 

看代碼: 

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
3.ø.ø 
info: 
title: "API" 
version: "l.ø.ø" 
paths: 
/products: 
description: 
get: 
summa ry: 
description: I

 

我爲/products這個資源添加了一個GET Action (get屬性), 而後我對這個get也進行了描述. 

summary至關因而對這個Action的一個歸納性描述, 而description則能提供更詳細的描述信息.  

這裏description是支持多行文本的, 可是在YAML裏面要想支持多行文本, 那麼string屬性必須以 | 管道符 開頭. 

注意, 這裏第1行 openapi下面的波浪線表示文檔驗證失敗. 

 

在OAS文檔裏, 一個操做必須在responses屬性裏提供至少一個響應: 

1 
2 
3 
4 
5 
6 
7 
8 
9 
lø 
11 
12 
13 
14 
15 
16 
17 
openapi: 3.ø.ø 
info: 
title: "API" 
version: 1 
paths : 
[products: 
description: 
get : 
summary: 
description: I 
responses: 
"2øø•• : 
description: I

一個Action可能有多種響應結果, 每種可能的響應結果都要在responses屬性中描述. 

每一個響應都以狀態碼進行標識, 而且必須包含一個description屬性. 

注意: 狀態碼數字必須用雙引號括起來, 由於它的類型本應該是字符串, 而這裏的200是一個數字. 

 

下面我再添加一個POST Action: 

1 
2 
3 
4 
5 
6 
7 
8 
9 
lø 
11 
12 
13 
14 
15 
16 
17 
18 
19 
2ø 
21 
22 
23 
24 
25 
26 
openapi: 3 .ø.ø 
info: 
title: "API" 
• "1.0.0" 
versxon : 
paths : 
/products : 
description: FR51J* 
get : 
summary: 
description: 
responses : 
"2øø•• : 
description: I 
post: 
summary: 
description: 
responses : 
"2øø•• : 
description: I

 

這裏仍是針對 /products 這個資源, 我就不過多解釋了. 

 

使用OpenAPI  JSON Schema 來描述 API 的數據 

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屬性也是可選的, 可是最好仍是寫上吧, 有個描述更好. 

 

使用JSON Schema來描述數據 

假設一個對象有三個屬性: 編號(string), 名稱(string), 價格(number). 那麼使用JSON Schema來描述它就應該是這樣的: 

type: object 
propert les: 
type: string 
type: string 
id: 
name: 
price: 
type: 
number

 

還沒完, 我還必須指出屬性是不是必填的, 而後我再加上一個remark屬性, 它不是必填的: 

type: object 
requi red : 
— id 
— name 
— price 
properties: 
id: 
type: 
name: 
type: 
price: 
type: 
remark: 
type: 
string 
string 
number 
string

 

JSON Schema 經過 required 這個集合屬性來表示哪些屬性是必填的. 

 

此外, 我還能夠在這裏添加 description 和 example (示例)屬性: 

type: object 
description: 
required : 
— id 
— name 
— price 
properties: 
id: 
type: string 
description: FRfifiiR 
example: ACØØØØI 
name: 
type: string 
exmaple: 
price: 
type: number 
example: 54.95 
rema rk : 
type: string 
exmaple:

 

此外 JSON Schema 還支持 對象屬性類型: 

type: obj ect 
description: —TFt% 
required: 
— id 
— name 
— price 
prope rt ies : 
id: 
type: string 
description: F%fifiiR 
example: ACØØØØI 
name: 
type: string 
exmaple: 
price: 
type: number 
example: 54.95 
remark: 
type: string 
exmaple: 
manufacturer: 
type: object 
description: 
requi red : 
— id 
— name 
propert les: 
id: 
type: number 
description: %ÜId 
example: 123 
name : 
type: string 
exmaple:

 

JSON Schema 的東西比較多, 具體能夠查找一下官方文檔. 

 

描述響應 

在OAS文檔裏, 操做響應返回的body裏的數據是用content屬性來表示: 

22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
responses: 
" 2øø•• : 
description: I 
content: 
application/ j son: 
schema : 
type: array 
description: 
items: 
type: obejct 
description: 
required: 
— name 
— price 
— manufacturer 
properties: 
description: FRfiID 
type: string 
name : 
type: string 
price: 
description: 
type: number 
rema rk: 
type: string 
manufactu rer: 
type: object 
description: 
requi red : 
— name 
properties: 
id: 
type: 
name: 
type: 
number 
string

 

這裏須要注意的就是該操做的結果是產品的數組, 因此類型是array, 而array 的 items屬性就包含着數組元素的schema. 

 

描述 body 參數 

像 POST 這樣的 Action, 它的參數是在請求的body裏面. 

body參數須要使用 requestBody屬性描述, 看代碼: 

type: string 
61 
62 
post: 
63 
summary: 
description: I 
64 
65 
requestBody: 
66 
description: 
67 
68 
content : 
application/j son: 
69 
schema : 
7ø 
required : 
71 
72 
— name 
— price 
73 
— manufacturerld 
74 
properties : 
75 
76 
name: 
type: string 
77 
price: 
78 
type: number 
79 
rema rk : 
8ø 
type: string 
81 
82 
manufacturerld: 
83 
type: number 
84 
responses: 
85 
"200" : 
86 
description: I 
87

這個 body 參數的內容也是使用 JSON Schema來描述的. 

 

描述路由參數 

像 api/products/{productId} 這樣的URI裏, productId就是一個路由/路徑參數. 

它能夠這樣描述: 

5 
6 
64 
65 
66 
67 
68 
69 
7ø 
71 
72 
73 
74 
75 
> 
paths : 
/products: 
/products/{p roductld}: 
description: 
delete: 
summary: 
parameters: 
- name: productld 
in: path 
required: true 
description: FhfiID 
schema: 
type: string 
components:

這裏面name的值必須和 {} 裏面的值同樣. 

in 的值爲 path, 表示是路徑參數. 

路徑參數是必填的, 因此 required 爲 true. 否則解析器會報錯. 

 

可複用組件 

OAS容許使用可複用的組件, 例如 schema, 參數, 響應等等, 使用它們的時候添加個引用就行. 

 

假設針對 /products 這個資源一共有兩個操做: 一個是返回一組產品, 另外一個返回單個產品. 這時候返回產品的JSON Schema就可使用一個可複用的schema. 

可複用的組件要放在components區域, 它是OAS文檔的一個根級屬性. 看例子: 

89 
9ø 
91 
92 
93 
94 
95 
96 
97 
98 
99 
løø 
IØI 
1Ø2 
1Ø3 
1Ø4 
1ø5 
1ø6 
1ø7 
1ø8 
1ø9 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
components: 
schemas : 
p roduct : 
type: object 
description: —TFt% 
requi red : 
— id 
— name 
— price 
- manufacturer 
properties : 
id: 
type: string 
description: FhfifiiR 
name: 
type: string 
price: 
type: number 
description: 
remark: 
type: string 
manufacturer: 
type: object 
description: 
required: 
— id 
— name 
properties: 
id: 
type: number 
name : 
type: Strind

這裏面, 可複用的schema被定義在schemas屬性裏, 每一個可重用的schema的名字就是schemas的值, 這裏就是product. 它下就包含着可重用的組件: 一個 JSON Schema. 

 

引用定義好的schema 

引用定義好的schema須要使用到JSON引用. JSON引用這個屬性的名字是$ref, 它的值是一個URL. 這個URL可指向本文檔內部甚至外部的組件. 這裏我只引用文檔內部的組件. 

 

62 
63 
64 
65 
66 
67 
68 
84 
85 
86 
87 
88 
89 
91 
92 
93 
post: 
summary: 
description: I 
requestBody: 
description: 
content: 
responses: 
"2øø•• : 
description: I 
content: 
application/ j son: 
schema : 
$ref: 'W/ components/schemas/product' 
components : 
schemas:

 

而針對那個 get Action的返回結果(數組類型), 須要把JSON引用放在 array 的 items屬性裏. 

 

可複用參數 

直接看代碼: 

65 
66 
67 
68 
69 
70 
71 
1ø2 
1ø3 
104 
105 
106 
1ø7 
108 
109 
description: 
delete: 
summa ry: 
pa ramete rs : 
— $ref: "#/components/parameters/productlå' 
components: 
> schemas: 
parameters: 
productld: 
name: productld 
in: path 
required: true 
description: F%ID 
schema : 
type: string

和可複用schema相似, 可複用參數也放在components下面, 它所在的區域是 parameters. 其引用方式也相似, 就不過多介紹了. 

 

除了在Action級別引用可複用參數, 在資源這個級別也能夠這樣作: 

6 
64 
65 
66 
67 
68 
69 
70 
/products: 
/products/{productld}: 
description: 
pa rameters : 
— $ref: "#/components/parameters/productld" 
delete: 
summary: 
components:

 

預覽 

 

相關文章
相關標籤/搜索