介绍:
OAS就是定义基于http的远程api的文档的一种规范
什么是API? API就是应用程序接口接口,比如说像编程中调用到的方法/函数,就是api之一,这个时候api是由方法的名称、参数、返回值等组成的。对于本地api来说,交互双方(调用者和提供api者)是处于同一台机器的,比如你自己机器的标准c库是由c编译器程序提供的。
而OAS就是聚焦于远程API的描述的,一般来说,提供API服务的一方称为提供方,而调用API的一方称为消费者。
OAS的优点:
文档校验和检查;
数据校验;
文档生成;
代码自动生成;
mock服务;
安全分析;
同时可供机器和人类阅读;
-
强大而完善的工具体系
使用 API 是计算机科学中的日常实践,因为它们的好处是毋庸置疑的。 举个最突出的例子:
API 提供信息隐藏:API 的任何一方(提供者和消费者)都不知道另一方的实现细节。 只要两者都遵守 API,就可以根据需要随意更改,而对方甚至不会注意到。
API 也称为契约,因为它们被认为是牢不可破的:提供者承诺不会改变其 API 并在未来几年继续兑现它。 有了这个承诺,消费者就可以开始开发他们的部件并充满信心地依赖 API 提供的功能。
现在,为了让所有相关方遵守相同的 API,必须对其进行精确定义。 下一节将介绍传统上如何实现这一目标。
一般来说,API都会配套有参考指南,用于解释如何来使用该api。而不幸地是,每个软件开发者或许都会面临以下的几种情况: 不熟悉文档
文档不全
过时的信息
读者无法理解的语言
为了解决这些问题,程序开发者往往需要大量时间来阅读源码、调试程序或者分析网络流量,这太浪费时间了
更现实的情况是,很多使用中会出现的问题,在你真真使用之前都难以发现
api描述文件(也称为契约)是一种机器可读的api规范(需要配合一些支持oas的工具,比如swagger)。它应该是尽可能完整且详细的(就是你几乎尽可能地把这个api涉及到细节都给描述出来了,从url到请求参数、响应参数、content-type、cookie、其他用到的header、以及包括对这些内容的描述、字段类型啥的全都给说清楚),虽然这不是强制(如果把一切都写清楚也不太现实)。这就是合同/契约 一样,你要是描述的越没有歧义,那它就越有用。
跟一般的人类可读的文档相比(也就是以往开发人员自行手写的比如markdown或者其他形式的文档),它最大的优势就是可以由机器自动处理,为本指南开头列出的好处敞开了大门。
只要是按照OAS编写的api描述,就可以很简单利用工具生成面向人类可读的文档;更进一步地说,它还能利用api描述直接生成即时可用的目标代码,这样生成的客户端代码是完全匹配api描述的,也避免了我们手动编写代码集成的时候一些错误。
OAS解释:
我们再次来介绍下OAS,OpenAPI规范(OAS)是一种与供应商无关的基于http的远程api描述格式。它最初基于2015年SmartBear Software捐赠的Swagger 2.0规范。
总而言之,它就是用于定义和描述基于http或者基于类似http的远程api的一种规范。
OAS规范:
整个OPENAPI的规范是很长的,对于新手来说是令人生畏的
所以我们需要先按主题、组织,简化浏览
OpenAPI文档结构:
OpenAPI文档是一个文本文件,一般是xxx.json或者xxx.yaml,是以json或者yaml格式来书写的
该文件被称为根文档并且可以被分割为多个json或者yaml文件 以让其更加清晰
一般来说,JSON不支持注释,需要:用逗号分隔字段,对象周围用花括号括起来,字符串周围用双引号括 起来,数组周围用方括号括起来。另一方面,YAML在数组项之前需要连字符,并且严重依赖缩进,这在大文件中可能很麻烦(在JSON中缩进完全是可选的)。YAML通常是首选的,因为它稍微减小了文件大小,但是这两种格式是完全可以互换的(只要使用YAML 1.2)。这些页面中的所有示例都将在YAML中给出。
然而,YAML是JSON的超集,这意味着这两种语法可以混合使用。虽然一般情况下不推荐这样做,但有时还是会派上用场的。例如
![p-images.jianshu.io/upload_images/26589460-1a456adb365a5a23.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
最小化的文档结构:
完全准确地说,OpenAPI文档就是一个完全符合OAS的单个JSON对象
这里有个站点可以以树形图的形式展示一个符合OAS的结构,可以用来帮助熟悉OAS规范
https://openapi-map.apihandyman.io/
最小结构中info 和openapi字段是必须的,此外paths,components,webhooks这3个字段中也必须有至少的其中一个存在
接着简单介绍下3个字段,openapi,info,paths
openapi:这个用来指示当前api文档所采用的OAS的版本
-
info:这个用来指示当前api的版本以及当前api的其他信息,注意这里指的当前我们自己写的api的信息,要注意它和openapi这个规范的版本有所不同
paths,这个用于指示当前api的所有端点,包括他们的参数以及所有可能的服务器响应。在自动生成服务器和客户端代码的时候主要就是依据这里的描述了,按照这个思路,我们可以写一个最小结构的符合OAS的文档出来
openapi: 3.1.0
info:
title: test
version: 0.0.1
paths: {}
OpenAPI端点endpoints
api端点在OAS中就是上面刚刚提到的paths对象
paths:需要注意的是paths字段的值是个对象,而不是一个数组,其中每个字段的键是端点名字,值是一个 路径项对象,就像这样:
paths: {
"/users": {路径项对象},
"/posts": {路径项对象}
}
路径都必须以 / 开头,为什么paths对象要采用对象而不是数组,是因为这样可以更加明显地表示paths对象中的端点名称是唯一的
path item object:路径项对象也是一个对象,其中的字段名是允许的http操作方法(get post put delete ...),值是一个操作对象(operation object), 需要注意的是在路径项对象上还可以指定所有操作都接收的公共属性,比如summary,description,比如
paths: {
"/users": {
"get": {操作对象},
"summary": "这是所有操作公共的摘要信息,当然要是个别操作有不同的话,也可以单独在该操作对象中指定"
},
"/posts": {路径项对象}
}
operation object操作对象,除了summary和description以外,操作对象一般来说还会描述操作的参数、载荷、可能的服务器响应等 paths:
/board:
get:
summary: Get the whole board
description: Retrieves the current state of the board and the winner.
parameters:
...
responses:
...
responses object响应对象集合,注意这里还是responses,带了个s,这个字段在操作对象中
用描述该操作有可能的各种服务器会给出的回答。这个对象中,每个字段的名字都是一个用引号括起来的http状态码,而它对应的值就是一个响应对象response object(注意这里没有带s了),进而描述每个响应对象的细节,注意,在responses object中至少要指定一个状态码,并且最好是一个表示成功的状态码,比如200.
response object响应对象,这里就是描述一个操作对象中具体的状态码对应的返回信息了,
这个对象中必须要有一个description,用于对该响应对象以及该状态码进行补充描述(本质上应该就是通用http状态码描述)
body of message:
上一步最后展示的是api端点中的响应对象,它位于操作对象中,实际上,在操作对象中除了description和responses以外,当然还有很多其他字段,比如还有request body object,跟响应对象相对应,它是请求对象。这里来介绍下在请求和响应对象中都会用到的一个字段: content,内容对象
content字段:它是标准媒体类型和OpenAPI媒体对象(OpenAPI Media Type Object)之间的映射对,比如:
responses: {
"200": {
content: {
"application/json": {OpenAPI媒体对象},
"test/html": {OpenAPI媒体对象}
}
}
}
这意味着,可以根据不同的格式来返回内容
Media Type Object媒体类型对象: 媒体类型对象就是一个媒体类型对应着的具体的内容结构,比如:
content:
application/json:
schema:
...
schema object模式对象: 模式对象用于定义数据类型,其可以是原子类型(整数,字符串),数组或者对象,取决于其中的type字段,注意,当schema的content位于responses就是定义的响应数据,当位于request body object中,就是定义的请求数据
注意,对于我们平时开发的json 格式的api来说的,一般content中的schema肯定都是object,因为我们都是返回一个对象,比如
这就是我们平时接口返回的一个典型例子,对于这种情况,我们应该将schema设置为object,然后再在object中进一步定义其下的各个字段
这里介绍各个数据类型的定义要求:
在schema对象中,通过type字段定义数据类型,type是一个字符串,可用的值为:number,string,boolean,array,object,根据type字段的值,会有一些配套的其他字段用于扩充定义
比如:对于string类型,就可以附加minLength和maxLength用于指定字符长度
对于integer类型,minimum和maximum字段可以用于指定最大最小值。
无论什么类型的值,都可以通过enum字段来限制该字段的值必须在它规定的范围内,enum是数组
对于数组类型,必须指定items字段,它也是一个schema对象,通过它来定义数组中的每个元素的类型。除此之外,数组的长度可以通过minItems和maxItems字段来指定
最后,对于对象类型的字段,必须通过properties字段来指定对象中的属性,properties是一个对象,其中的键是字段名,值是schema对象
content:
application/json:
schema:
type: object
properties:
productName:
type: string
productPrice:
type: number
parameters和requestBody
OAS提供了两种机制来指定输入数据,parameters和request body(消息体).parameters用于标识资源,request body用于提供资源的内容
parameter对象: 在路径项对象和操作对象中的parameters字段是一个包含parameter对象的数组,当在路径项对象中提供时,parameters是与那一个路径下的所有操作对象共享的
每一个parameter对象描述一个参数,使用如下必须的字段:
- in(string): 参数所处的位置
可选值: - path,也就是说是位于路径的一部分,也就是说我们在指定路径的时候,可以将路径的一部分通过参数来代指,比如说路径其实可以这样指定, /users/{id} ,而且如果这样指定了路径的话,那么久必须通过parameter中的对应一个名为id的参数来指定,同时需要注意的是,如果是路径参数的话,那么该parameter对象中,必须有required: true 这一对属性值
- query: 就是附加在url的?后面的参数值
- header: 作为自定义的HTTP header部分,注意它的名称是大小写敏感的
name(string):参数名字,区分大小写,在每个位置中必须唯一
额外的可选字段:
description:描述信息,required(boolean)是否必填
parameter type:
大多时候,指定参数的数据类型都是通过schema对象(也就是在parameter对象中的schema字段)来指定。schema对象允许定义原子或者复杂的数据类型(数组或者对象)
parameters:
-
name: id
in: query
schema:
type: integer
minimum: 1
maximum: 100
在更高级的场景中,会通过content字段来指定字段类型,它提供一个单入口(媒体类型到OAS媒体类型的)的映射。注意:schema或者content二者必须存在其一。它们不能同时出现
request body object:请求体是通过在操作对象中的requestBody字段来指定的,唯一的必填字段就是content
components和$ref
复用描述,很常见的情况是文档太大以致于不好管理。为此我们可以通过复用机制来移除冗余的部分。
components对象:通过在根节点下的components字段定义,包含了要复用的对象的定义
当然,并非所有的对象都是可以复用的,只有那些作为components对象的字段才可以列出来,比如schemas,responses,parameters
组件对象中的每个字段都是一个将组件名称与要重用的对象配对的映射。这些对象的类型必须与父字段匹配,例如,模式映射中的对象必须是模式对象;responses映射中的对象必须是response对象
引用对象:任意一个Components对象中的OpenAPI对象都可以通过引用对象来代替。
引用对象:通过 "$ref": "指向引用对象的uri资源路径",来使用
提供示例: example和examples
api服务器servers:
servers对象提供了API的基础URL,通过servers字段来定义,它是一个数组,它可以存在于根节点、路径项对象或者操作对象中。
servers是一个数组,其中的每一个元素就是一个server对象,至少要有一个url字段,用于表示基础路径。一个可选的description字段,当不同层级都有指定servers时,只有层级最低的那一级会生效。例如:
servers:
- url: https://server1.com
paths:
/users:
get:
servers:
- url: https://server2.com
```yaml
/users这个路径实际应该是追加在server2后面的,完整的请求url是 [https://server2.com](https://server2.com)/users
server url中可以包含变量,在url中通过{}分隔,这些变量必须在进一步在server对象的variables中进行配置。variables是一个对象,它是一个变量名和变量对象之间的映射关系。
服务器变量对象有以下字段:
default(string): 这是一个必填字段,如果没有其他值要提供的话
enum(字符串数组):如果存在的话,那么这个数组就会列出该变量的合法值,默认值也必须出现在其中
description: 该字段的描述