How can I display multiple ResponseDTOs' schemas in Swagger/NestJS?

Dai*_*ess 7 swagger swagger-ui nestjs nestjs-swagger

I have this route which can return one of these two different DTOs:


  @Get()
  @ApiQuery({ name: 'legacy', description: "'Y' to get houses legacy" })
  async findAllHouses(
    @Query('legacy') legacy: string,
  ): Promise<HousesDto[] | HousesLegacyDto[]> {
  ...
  }
Run Code Online (Sandbox Code Playgroud)

I want to display both of these ResponseDTOs in swagger. I've tried this decorator:

  @ApiOkResponse({
    schema: { oneOf: refs(HousesDto, HousesLegacyDto) },
  })
// OR
  @ApiOkResponse({
    schema: {
      oneOf: [
        { $ref: getSchemaPath(HousesDto) },
        { $ref: getSchemaPath(HousesLegacyDto) },
      ],
    },
  })
Run Code Online (Sandbox Code Playgroud)

with @ApiExtraModels() on top of DTO classes and @ApiProperty() on each properties.

But I still get empty objects in Swagger and I suppose it would not have even taken array types in consideration.

How can I display both of these schemas properly?

swaggerOneOfSchema

小智 14

在我看来,很多非常晦涩的解决方案已经到处发布,所以我将尽力澄清需要做什么。

您有两个 DTO:

export class SomeStatusDto {
  @ApiProperty({
  description: 'Id',
  example: 1,
  })
  @IsNumber()
  id: number;

  @ApiProperty({
  description: 'Status',
  example: 'in_progress',
  })
  @IsString()
  status: string;
}

export class ErrorStatusDto {
  @ApiProperty({
  description: 'Id',
  example: 1,
  })
  @IsNumber()
  id: number;

  @ApiProperty({
  description: 'Error',
  example: 'Some error string',
  })
  @IsString()
  error: string;
}
Run Code Online (Sandbox Code Playgroud)

然后你就有了你的控制器:

  @UseGuards(AccountTypesGuard)
  @ApiOperation({ summary: 'Get status of...' })
  @Get('status')
  @ApiExtraModels(SomeStatusDto, ErrorStatusDto)
  @ApiOkResponse({
    schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
  })
  async getPullStatus(
    @Request() req,
    @Param('id', ParseIntPipe) someId: number,
  ): Promise<SomeStatusDto | ErrorStatusDto> {

    // check if someId belongs to user
    const idBelongsToUser = await this.myService.validateSomeId(
      req.user.id,
      someId,
    );

    if (!idBelongsToUser) {
      throw new ForbiddenException(
        `SomeId does not belong to user (someId=${someId}, userId=${req.user.id})`,
      );
    }

    const key = `status-${someId}`;
    const response = await this.redisService.getByKey(key);
    return response ? response : {};
  }
Run Code Online (Sandbox Code Playgroud)

请注意下面的解决方案。您需要将 DTO 作为 @ApiExtraModels() 引用,然后可以将它们添加为 schema 中的 anyOf: refs(...) 。

  @ApiExtraModels(SomeStatusDto, ErrorStatusDto)
  @ApiOkResponse({
    schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
  })
Run Code Online (Sandbox Code Playgroud)

希望这对某人有帮助:)


小智 2

第一个模式

第二个模式

所以我遇到了类似的问题,这就是如何获得上图所示的输出。

使用@ApiResponse装饰器,您可以使用示例属性设置两个响应,请尝试下面的代码示例

@ApiResponse({
    status: 200,
    description: 'Successful response',
    content: {
      'application/json': {
        examples: {
          HousesDto: { value: HousesDto },
          HousesLegacyDto: { value: HousesLegacyDto },
        },
      },
    },
})
Run Code Online (Sandbox Code Playgroud)