使用 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:

 

预览 

 

相关文章
相关标签/搜索