OpenAPI 3-写入时属性是可选的,但读取时则必需

时间:2019-03-04 16:36:47

标签: rest swagger openapi

我的资源有一个ID(典型情况)。

它还有一个 slug ,它是人类可读但仍然唯一的标识符(主要是美化URL)。

创建资源时,此 slug 可选。如果客户端提供了一个,则说明该客户端正在使用;否则,服务器将生成一个。

但是,在读取资源时,该子弹是必需的。

我们确实希望清楚区别,所以任何阅读OpenAPI规范的工具都知道确切的期望。

这当然可以通过使用与allOf修饰符链接的不同模式的混合来实现(请参见下面的示例),但是我想避免执行这种组合(假设它首先与工具一起使用) )。

所以我的问题是:

OpenAPI> = 3.0.2中是否有一种方法可以声明属性required-readOnly和optional-writeOnly?

使用成分的解决方案:

openapi: 3.0.2
info:
  title: Person API
  version: 1.0.0

paths: 
  '/persons/{person-slug}':
    get:
      parameters:
        - $ref: '#/components/parameters/PersonSlug'
      responses:
        200:
          description: Information on a person.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SlugRead'
                  - $ref: '#/components/schemas/Person'
    post:
      parameters:
        - $ref: '#/components/parameters/PersonSlug'
      responses:
        200:
          description: Information on a person.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SlugWrite'
                  - $ref: '#/components/schemas/Person'

components:

  parameters:

    PersonSlug:
      name: 'person-slug'
      description: Human readable unique ID of a person.
      required: true
      in: path
      schema:
        type: string

  schemas:

    SlugRead: # required
      required:
        - slug
      properties:
        slug:
          type: string
          readOnly: true

    SlugWrite: # not required
      properties:
        slug:
          type: string

    Person:
      required:
        - first_name
        - last_name
        - birth_date
      properties:
        first_name:
          type: string
        last_name:
          type: string
        birth_date:
          type: string
          format: date    

2 个答案:

答案 0 :(得分:2)

对于将来偶然发现这个问题的任何人,我使用基本架构和派生架构解决了特定操作。

Person:
  properties:
    id:
      type: integer
      readOnly: true
    name:
      type: string
    slug:
      type: string

PersonWRITE:
  allOf: # name is required, slug is optional and id is not available
    - $ref: '#/components/schemas/Person'
    - required: [name]

PersonREAD:
  allOf: # everything is available and required
    - $ref: '#/components/schemas/Person'
    - required: [id, name, slug]

它本质上是 OP 的解决方案,但移到了组件级别,因此您不必在请求/响应定义中使用“allOf”。


编辑: 请注意,以下内容无效:

PersonWRITE: #wrong
  $ref: '#/components/schemas/Person'
  required: [name]

正如文档中所述,Any sibling elements of a $ref are ignored. This is because $ref works by replacing itself and everything on its level with the definition it is pointing at.

键是allOf,它结合了列表中对象的所有属性。在 $ref 扩展后,模式看起来像这样(仍然是一个有效的 yaml,我只是稍微对它进行了 jsonified,以指出数组元素实际上是两个属性将被组合的对象):

PersonWRITE:
  allOf: [
    {
      properties: {
        id:   { type: integer, readOnly: true },
        name: { type: string },
        slug: { type: string }
      }
    },
    {
      required: [name]
    }
  ]
    

答案 1 :(得分:0)

看不到如何准确地实现 ,但我认为可以通过对期望的(只写)vs分配的(只读)字段使用单独的字段来定义效果鼻涕虫:

Person:
  required:
    - first_name
    - last_name
    - birth_date
    - assigned_slug
  properties:
    first_name:
      type: string
    last_name:
      type: string
    birth_date:
      type: string
      format: date
    assigned_slug:
      type: string
      readOnly: true
    desired_slug:
      type: string
      writeOnly: true

不知道是否有任何工具会用它做正确的事!