代码之家  ›  专栏  ›  技术社区  ›  smactive

招摇过市:变量模式形状取决于字段值

  •  0
  • smactive  · 技术社区  · 8 年前

    我有一个模型定义为:

    Event:
      type: object
      properties:
        id:
          type: string
        timestamp:
          type: string
          format: date-time
        type:
          type: string
          enum:
            - click
            - open
            - sent
        click:
          type: object
          properties:
            url:
              type: string
            title:
              type: string
        open:
          type: object
          properties:
            subject:
              type: string
        sent:
          type: object
          properties:
            subject:
              type: string
            from:
              type: string
            to:
              type: string
    

    然而,形状实际上是不同的,这取决于 type 枚举字段。它可以是三个之一,我试图定义 examples

    如您所见,下面显示了三个示例,每个示例根据不同的 类型 . 这就是API的行为方式,但记录这种预期行为并不容易。

      examples:
        application/json:
          - id: >
              ad1b12f0-63a8-47b5-9820-3e447143ce7e
            timestamp: >
              2017-09-29T16:45:20.000+00:00
            type: click
            click:
              url: >
                www.some-website-somewhere.org/12345
              title: >
                Click here!
          - id: >
              d9e787fa-db49-4bd8-97c3-df45f159295c
            timestamp: >
              2017-09-29T16:45:20.000+00:00
            type: open
            open:
              subject: >
                Have you seen this?
          - id: >
              30adc194-0f5f-4889-abd4-4fa964d0bb42
            timestamp: >
              2017-09-29T16:45:20.000+00:00
            type: sent
            sent:
              subject: >
                Have you seen this?
              from: >
                bill@office.gov
              to: >
                mon@gmail.com
    

    我读到一些地方提到这是不可能的,但我希望能找到一些“开箱即用”的思考者来帮助我找到解决方案。

    1 回复  |  直到 8 年前
        1
  •  1
  •   Helen    7 年前

    这可以使用 model inheritance/composition discriminator .

    首先,定义基础模型 Event 只包含公共属性,并标记 type 属性为 鉴别器 :

    definitions:
      Event:
        type: object
        discriminator: type
        required:
          - type  # discriminator property is required
        properties:
          id:
            type: string
            example: ad1b12f0-63a8-47b5-9820-3e447143ce7e
          timestamp:
            type: string
            format: date-time
            example: 2017-09-29T16:45:20.000+00:00
          type:
            type: string
            enum:
              - click
              - open
              - sent
    

    然后从基础继承单击/打开/发送的模型 事件 型号via allOf . 子模型的名称必须与鉴别器属性的值相同。在您的示例中,模型必须命名为 click , open sent . 如果使用Swagger UI,可以添加 title 要覆盖 模型名称。

      click:
        title: ClickEvent
        allOf:
          - $ref: '#/definitions/Event'
          - type: object
            properties:
              click:
                type: object
                properties:
                  url:
                    type: string
                    example: www.some-website-somewhere.org/12345
                  title:
                    type: string
                    example: Click here!
    

    在操作中,使用基础模型( )作为请求或响应模式:

    responses:
      200:
        description: OK
        schema:
          $ref: '#/definitions/Event'
    

    客户端应该检查鉴别器属性的值(在本例中- 类型 )决定使用哪个继承模型。

    注意:对于Swagger UI用户: Swagger UI和Swagger Editor当前不支持基于 鉴别器 this issue


    在里面 OpenAPI 3.0 它更容易-你可以简单地使用 oneOf 为请求或响应定义备用模式。

    responses:
      '200':
        description: OK
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/ClickEvent'
                - $ref: '#/components/schemas/OpenEvent'
                - $ref: '#/components/schemas/SentEvent'
              # Optional mapping of `type` values to models
              discriminator:
                propertyName: type
                mapping:
                  click: '#/components/schemas/ClickEvent'
                  open:  '#/components/schemas/OpenEvent'
                  sent:  '#/components/schemas/SentEvent'