用请求主体数据以外的其他数据自动填充DTO字段

时间:2019-10-09 16:14:26

标签: node.js typescript nestjs

我有一个CreateFolderDto类,其中有两个只读字段:

export class CreateFolderDto {
    public readonly name: string
    public readonly user_id: number
}

我有一个控制器,该控制器是:

@UseGuards(AuthGuard('jwt'))
@Post()
public create(@Request() req, @Body() createFolderDto: CreateFolderDto) {
    return this.folderService.create(createFolderDto)
}

发送到我的控制器的请求是一个很好的请求,我只发送name格式的json,并且标头中带有accessTokenaccessToken允许我通过user_id从请求中获得req.user.id

DTO字段user_id不会自动填充。我想自动填写。

这是一种自动填充createFolderDto.user_id变量的方法吗?

1 个答案:

答案 0 :(得分:1)

@Body仅将实际的请求正文包装到CreateFolderDto类的实例中。由于到达端点的正文没有这样的字段,因此您需要手动添加它。

通常,可以使用DTO的自定义构造函数添加聚合字段:

export class CreateFolderDto {
    public readonly name: string
    public readonly session_uuid: string

    constructor(bodyValue: any = {}) {
       this.name = bodyValue.name
       this.session_uuid = generateUuid()
    }
}

但是在您的情况下,user本身附加到request上,因此我相信您有以下选择:

  1. 检出将user附加到自身的代码。如果您使用的是NestJS文档中介绍的JWT Auth,则不能采用这种方式。

  2. 您可以编写自定义拦截器:

Injectable()
export class ExtendBodyWithUserId implements NestInterceptor {
  async intercept(context: ExecutionContext, next: CallHandler) {
    const request = context.switchToHttp().getRequest()
    request.body.user_id = request.user
    return next.handle()
  }
}

// usage
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(ExtendBodyWithUserId)
@Post()
public create(@Request() req, @Body() createFolderDto: CreateFolderDto) {
    return this.folderService.create(createFolderDto)
}

最后但并非最不重要的一些个人建议。考虑一下您将使用这个拦截器作为扩展的程度,因为过多的“ extras”都会使代码库膨胀。

我建议将folderService签名更改为: create(createFolderDto: CreateFolderDto, user: User),其中文件夹dto仅具有名称,而没有与用户相关的条目。您保持一致,分离和明确的意图。在create的实现中,您可以进一步传递user.id。 按照这种方式,您不必编写自定义拦截器。

选择您的方式,并确保代码库中的一致性与您同在!