OpenAPI Specification 系列笔记 II

发布于:2025-09-05 ⋅ 阅读:(21) ⋅ 点赞:(0)

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/#objects

    An empty list required: [] is not valid. If all properties are optional, do not specify the required keyword.
    意思就是,对于 openAPI specs 来说,required: [] 不是一个合法的语法,如果所有的属性都为可选项,那么就别加 required 这个属性

  • readOnly & writeOnly
    如其名
  • additionalProperties
    这个算是添加了扩展字段类型的能力,相当于说如果有任何位置的属性,只要返回值满足固定需求即可,如:
    type: object
    additionalProperties:
      type: string
    
    即表示该对象可以包含任意的键值对,只要值的数据类型为字符串即可
  • minProperties & maxProperties
    即一个对象中可以最多/少包含的属性数量

array

主要也是有 3 个属性:

  • items
  • minItems and maxItems
  • uniqueItems
    boolean,限定数组中是否能有重复元素

inheritance & polymorphism

这章主要放的是 3.0 的内容,下一篇笔记会基于额外的学习补充一下 3.1 中怎样更加灵活的使用新功能

allOf

allOf 实现了 inheritance 这一概念,在 specs 中使用 allOf 则表明当前对象需要满足所有的条件

以之前的 Product 为例,下面新声明了几个新产品,如 MobileLaptop ,他们作为 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"


网站公告

今日签到

点亮在社区的每一天
去签到