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

Ade*_*ack 3 rest swagger openapi

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

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

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

但是,在读取资源时需要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    
Run Code Online (Sandbox Code Playgroud)

Pap*_*och 5

对于将来偶然发现这个问题的人,我使用基本模式和派生模式解决了这个问题以进行特定操作。

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]
Run Code Online (Sandbox Code Playgroud)

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


编辑:请注意以下将不起作用:

PersonWRITE: #wrong
  $ref: '#/components/schemas/Person'
  required: [name]
Run Code Online (Sandbox Code Playgroud)

正如文档中所述, $ref 的任何同级元素都将被忽略。这是因为 $ref 的工作原理是用它指向的定义替换自身及其级别上的所有内容。

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

PersonWRITE:
  allOf: [
    {
      properties: {
        id:   { type: integer, readOnly: true },
        name: { type: string },
        slug: { type: string }
      }
    },
    {
      required: [name]
    }
  ]
    
Run Code Online (Sandbox Code Playgroud)