NestJs/swagger: 定义没有 DTO 的引用模式 类

NestJs/swagger: Define ref schemas without DTO classes

我有一个应用程序,我根据 open-api 规范将 API 响应模式定义为普通 javascript 对象。目前,我将其传递给@nestjs/swagger 中的 ApiResponse 装饰器,如下所示:

class CatsController {

  @Get()
  @ApiResponse({
    status: 200,
    schema: catSchema // plain js object imported from another file
  })
  getAll() {}
}

效果很好。但是,输出 open-api 规范包含每个使用 catSchema 的端点的详细模式。 相反,我希望输出 swagger 文件在 components 部分下具有 catSchema,并在路径部分中具有相应的 $ref

components:
  schemas:
    Cat:
      properties:
        name:
          type: string
paths:
  /cats/{id}:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Cat'

到目前为止,似乎唯一的方法是将模式定义为 DTO class 并为每个 class [=38= 使用 ApiProperty 装饰器].就我而言,这意味着我必须将 open-api 规范中的所有普通对象模式重构为 DTO classes.

有没有办法将原始模式提供给库并获得预期的结果?

// instead of this:
class CatDto {
  @ApiProperty()
  name: string;
}

// I want to do:
const catSchema = {
  type: 'object',
  properties: {
    name: { type: 'string' }
  }
}

经过日复一日的反复试验,我在 Javascript.

中使用了一个有趣的技巧来解决这个问题

首先,我将 open-api 规范创建为普通对象(如问题中所问)。然后将它传递给一个新的装饰器,魔法就在这里发生了。

在装饰器中,我创建了一个具有预定义名称的 DTO class,并将属性从普通对象映射到 DTO class。棘手的部分是动态地给它起一个名字。这可以通过以下技术实现。

const dynamicName = 'foo'; // passed as a parameter to the decorator

class IntermediateDTO {
  @ApiProperty(schema) // schema as a plain object
  data: any;
}

const proxyObject = {
  [dynamicName] = class extends IntermediateDTO {}
}

通过使用代理对象,并将 class extends IntermediateDTO {} 分配给其中的 属性,该条目会动态获得一个名称。现在可以将这个具有动态名称的新 DTO 传递给 @nestjs/swaggerApiResponse 装饰器以达到预期的结果。

不知道是不是你想要的,我是这样做的

@ApiResponse({
    status: 200,
    schema: {
      example: // write the response you want here
      [    
        {
          userId: 1,
          name: 'name',
          
        },
      ],
    },
  })

我想这也可以通过使用 getSchemaPathApiExtraModels:

来实现
import { ApiExtraModels, ApiResponse, getSchemaPath } from '@nestjs/swagger';

@ApiExtraModels(CatDto) // for CatDto to be found by getSchemaPath()
@ApiResponse({
  schema: {
    '$ref': getSchemaPath(CatDto)
  }
})

关于额外型号的更多信息:https://docs.nestjs.com/openapi/types-and-parameters#extra-models


In my case, that means I have to refactor all the plain object schemas in open-api spec to be DTO classes.

不需要手动标注对象,也可以使用这个插件,就是opt-in:https://docs.nestjs.com/openapi/cli-plugin