OpenAPI Specification 系列笔记 II
这个系列的学习笔记总共会有三篇,上一篇在: OpenAPI Specification 系列笔记 I,下一篇大体是写完了,不过具体发布的时间可能会稍微晚一些,可能要等我折腾完 postman 了……?
repo 地址在:
https://github.com/GoldenaArcher/open-api-3.x-study
components
components
可以重复使用一些已经声明好的定义,下面是一个关于 orderId
的声明—— orderId
已经在不少地方被重复使用过了:
components:
parameters:
orderIdQueryParam:
name: orderId
in: query
required: true
schema:
type: integer
minimum: 1
maximum: 2147483647 # maximum value for a 32-bit signed integer
description: The ID of the order to delete
example: 303
下一步就是代替原本 cv 的代码,通过使用 #/components/parameters/orderIdQueryParam
的引用进行复用:
⚠️: $refs
可以引用任何合法的 JSON Pointer 或外部文件 URI,但是将可服用的组件放到 components
中是一个 common practice
schema
schema
是在 components
下的另一个属性,这其中大部分放的是 data schema,如下面会复用 address
这个重复了好几次的 schema:
schemas:
Address:
type: object
properties:
street:
type: string
description: Street address
city:
type: string
description: City
state:
type: string
description: State
zipcode:
type: string
description: ZIP code
required: ["street", "city", "state", "zipcode"]
response
response
同理:
responses:
InternalServerError:
description: An unexpected error occurred
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: "Internal Server Error"
code:
type: integer
example: 500
data types
下面简单讲一下 openAPI specs 的数据类型,也就是可以在 object
中用的部分
integer & number
这个比较简单,参照下面的表格即可:
type | format |
---|---|
number | float |
double | |
integer | int32 |
int64 |
string
string 主要有下面几种类型:
- date,ISO 8601 格式,如
2025-08-30
- date-time,ISO 8601 格式,如
2025-08-30T10:15:30Z
- password
- byte
- binary
同时也可以使用 pattern
去使用正则强化约束,如:
type: string
pattern: "^[A-Z]{3}-[0-9]{4}$"
除此之外也可以搭配 minLength
或者 maxLength
强化约束
其他的特殊用法还包括 enum
的使用,如:
type: string
enum: [small, medium, large]
boolean
只有 true
& false
两个值
null
这是一个比较特殊的属性,OAS 3.0 是没有的,只能通过 nullable: true
去实现
但是 OAS 3.1 可以使用 null
,同时也禁用了 nullable: true
files
在 OAS 3.0 中被 binary
所取代了,在 OAS 2.0 中是一个合法的类型
object
之前也展示过具体的用法了,下面是对属性的一些解释:
required
可以使用一个空数组,语法上没什么问题(亲测),但是通过官方文档 : https://swagger.io/docs/specification/v3_0/data-models/data-types/#objectsAn empty list
required: []
is not valid. If all properties are optional, do not specify therequired
keyword.
意思就是,对于 openAPI specs 来说,required: []
不是一个合法的语法,如果所有的属性都为可选项,那么就别加required
这个属性readOnly
&writeOnly
如其名additionalProperties
这个算是添加了扩展字段类型的能力,相当于说如果有任何位置的属性,只要返回值满足固定需求即可,如:
即表示该对象可以包含任意的键值对,只要值的数据类型为字符串即可type: object additionalProperties: type: string
minProperties
&maxProperties
即一个对象中可以最多/少包含的属性数量
array
主要也是有 3 个属性:
items
minItems
andmaxItems
uniqueItems
boolean,限定数组中是否能有重复元素
inheritance & polymorphism
这章主要放的是 3.0 的内容,下一篇笔记会基于额外的学习补充一下 3.1 中怎样更加灵活的使用新功能
allOf
allOf
实现了 inheritance 这一概念,在 specs 中使用 allOf
则表明当前对象需要满足所有的条件
以之前的 Product
为例,下面新声明了几个新产品,如 Mobile
和 Laptop
,他们作为 Product
的子类,就需要包含 Product
所有的属性,同时再包含自己特有的属性,具体使用方法如下:
Product:
type: object
properties:
productId:
type: integer
name:
type: string
price:
type: number
format: float
categoryName:
type: string
quantity:
type: integer
description: |
**Quantity** is the number of items available `in stock`
for the product.
Mobile:
allOf:
- $ref: "#/components/schemas/Product"
- type: object
properties:
networkType:
type: string
enum:
- 2G
- 3G
- 4G
- 5G
required: [networkType]
Laptop:
allOf:
- $ref: "#/components/schemas/Product"
- type: object
properties:
ram:
type: string
enum:
- 4GB
- 8GB
- 16GB
- 32GB
required: [ram]
oneOf
oneOf
实现了 polymorphism 这一特性,即当前对象只要满足提供的任意属性即可
目前没有什么特别好的例子,这里就用了一个新的 endpoint 模拟 oneOf
的功能:
/orders/one-of:
post:
tags:
- "Orders"
summary: Create a new order with one of the products
description: Creates a new order with one of the products provided in the request body
requestBody:
content:
application/json:
schema:
type: object
properties:
products:
type: object
oneOf:
- $ref: "#/components/schemas/Mobile"
- $ref: "#/components/schemas/Laptop"
address:
$ref: "#/components/schemas/Address"
required: ["products", "address"]
如果是实际的运用场景的话,这种地方比较适合接入接口,比如说支付接口支持支付宝、微信、信用卡、银联等,或者是下载/上传的业务场景,可以支持 pdf、word、图片等不同格式
anyOf
这个是满足任意一个需求即可,在写 response 的时候会用到 anyOf
,主要是现在对接的一些接口实现比较老派,日常返回 200 但是报错信息在 response 中,使用 anyOf
会比较好处理一些
/orders/any-of:
get:
tags:
- Orders
summary: Get orders with any of the products
description: Returns a list of orders that contain any of the specified products
parameters:
- $ref: "#/components/parameters/orderIdQueryParam"
- name: fetchType
in: query
required: true
schema:
type: string
enum:
- summary
- details
description: >
Fetch Type:
* `summary` - will provided Order Summary
* `details` - will provide Order Summary & Order Address
responses:
"200":
description: Return product details
content:
application/json:
schema:
anyOf:
- $ref: "#/components/schemas/OrderSummary"
- $ref: "#/components/schemas/OrderAddress"
not
这里提一下,确实想不到有什么业务场景可以用这个……
其他
补充一下其他比较重要的内容,基本上 OAS 的主要内容就在上篇笔记和本篇里了
operationId
对当前 endpoint 提供一个唯一的标识符,用 codegen 生成代码的时候, operationId
会被直接用作生成的方法名
OAS 文档中也可以通过 operationId
进行引用和参考——一般来说这种用法比较少,如果需要重复的定义,可能已经在 components
中定义过,并且可以直接被调用。在需要强上下文链接,如在 A 接口的返回里附带调用 B 接口的入口这样的业务场景,在 links
中用 operationId
的情况就会多不少了
deprecated
用这个标记后,文档上对应的 endpoint 会灰掉:
links
这个部分就是上面提到的,使用 operationId
的地方了
这个 YAML 分成两个部分来说,首先是在 components → links
下创建一个可以重复使用的 links
的模板,随后在创建 Order 下面的 response 中,将返回值中的 orderId
,通过 links
链接起来
这代表, GetOrderByOrderId
,也就是指向了 getOrders
中的 query parameter 所需要的值,就是 POST request 成功后返回的 orderId
# under component to create reusable links
links:
GetOrderByOrderId:
description: |
The `orderId` value returned in the response can be used as the input parameter in `Get /orders`.
operationId: getOrders
parameters:
orderId: "$response.body#/orderId"
# under the post order, AKA create new order endpoint's response
responses:
"201":
description: Order created successfully
links:
GetOrderByOrderId:
$ref: "#/components/links/GetOrderByOrderId"
⚠️:我又重新看了一下整个案例 OAS,发现这个 links
的用法不是最好的,创建 order 后返回的 orderId
其实和 /orders/{orderId}
具有强关联性,而 /orders
中的 query parameter 应该是作为可选项
这样可以形成一个比较完整的链式调用,即, POST /orders
返回的一个 order 对象,order 对象中包含一个 orderId
,可以直接被 GET /orders/{orderId}
所调用,因为二者本来就是同一个引用
custom info
这个作为 customized 信息可以被放到 swagger 中,使用方法如下:
info:
x-custom-info:
- "This is a custom field"
- "You can add any custom information here"
需要注意的是,这些信息是不会被 swagger UI 渲染的,如果有一些 UI 库可以渲染这些内容,那么是第三方的支持,而不是官方支持
但是这个用法蛮多的,我在做一点测试,成功了会放到第三章笔记里面进行补充
external docs
在 root 下或者是 path 下都可以使用,就是引用一个外部文档
externalDocs:
description: "Find out more about EazyShop"
url: "http://www.example.com/docs"