NestJs:如何让 Body 输入形状与实体的 DTO 不同?

Car*_*ven 4 javascript serialization node.js typescript nestjs

我的照片和标签对象有 DTO,如下所示:

export class PhotoDto {
    readonly title: string
    readonly file: string
    readonly tags: TagDto[]
}

export class TagDto {
    readonly name: string
}
Run Code Online (Sandbox Code Playgroud)

我使用PhotoDtoin myphoto.service.ts并最终使用 inphoto.controller.ts来创建照片:

// In photo.service.ts
async create(createPhotoDto: PhotoDto): Promise<PhotoEntity> {
   // ...
   return await this.photoRepo.create(createPhotoDto)
}

// In photo.controller.ts
@Post()
async create(@Body() createPhotoDto: PhotoDto): Promise<PhotoEntity> {
   // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,API 主体中的输入应具有以下结构:

{
   "title": "Photo Title",
   "file": "/some/path/file.jpg",
   "tags": [
      {
         "name": "holiday"
      },
      {
         "name": "memories"
      }
   ]
}
Run Code Online (Sandbox Code Playgroud)

如何更改 的输入形状Body以接受此结构?

{
   "title": "Photo Title",
   "file": "/some/path/file.jpg",
   "tags": ["holiday", "memories"]
}
Run Code Online (Sandbox Code Playgroud)

我尝试创建 2 个不同的 DTO,一个CreatePhotoDto和一个InputPhotoDto,一个用于控制器中所需的输入形状,另一个用于服务和实体,但这最终非常混乱,因为在 2 个 DTO 之间进行转换需要做很多工作.

什么是从具有不同的输入形状的正确方法Body一的Post请求,然后它已经变成了需要通过实体使用DTO?

Kim*_*ern 9

您可以使用以下的自动转换ValidationPipe()

1)添加ValidationPipe到您的控制器:

@UsePipes(new ValidationPipe({ transform: true }))
@Post()
async create(@Body() createPhotoDto: PhotoDto): Promise<PhotoEntity> {
   // ...
}
Run Code Online (Sandbox Code Playgroud)

2)添加一个@Transform到你的PhotoDto

// Transforms string[] to TagDto[]
const transformTags = tags => {
  if (Array.isArray(tags)) {
    return tags.map(tag => ({name: tag}))
  } else {
    return tags;
  }
}


import { Transform } from 'class-transformer';
export class PhotoDto {
    readonly title: string
    readonly file: string
    @Transform(transformTags, {toClassOnly: true})
    readonly tags: TagDto[]
}
Run Code Online (Sandbox Code Playgroud)