如何使用配置对象和依赖项创建 NestJs Pipe?

tom*_*c38 4 nestjs

我想将配置字符串传递给管道,但也想注入服务。NesJs 文档描述了如何独立而不是一起完成这两项工作。举个例子:

管道.ts

@Injectable()
export class FileExistsPipe implements PipeTransform {

  constructor(private filePath: string, db: DatabaseService) { }

  async transform(value: any, metadata: ArgumentMetadata) {
    const path = value[this.filePath];
    const doesExist =  await this.db.file(path).exists()
    if(!doesExist)  throw new BadRequestException();
    return value;
  }
}
Run Code Online (Sandbox Code Playgroud)

控制器.ts

@Controller('transcode')
export class TranscodeController {

  @Post()
  async transcode ( 
    @Body( new FileExistsPipe('input')) transcodeRequest: JobRequest) {
    return await this.videoProducer.addJob(transcodeRequest);
  }

Run Code Online (Sandbox Code Playgroud)

基本上,我希望能够将属性名称传递到我的管道(例如'input'),然后让管道查找请求中的属性值(例如const path = value[this.filePath]),然后查看该文件是否存在于数据库中。如果没有,则抛出 Bad Request 错误,否则继续。

我面临的问题是我需要 NestJs 来注入我的 DataBaseService。对于当前的示例,它不会,并且我的 IDE 给出一个错误,new FileExistsPipe('input')仅传递了一个参数,但需要两个参数(例如 DatabaseService)。

有办法实现这个目标吗?

Cha*_*ran 7

编辑:我刚刚检查了你的存储库(很抱歉之前错过了)。你DatabaseServiceundefinedFIleExistPipe因为你在 中使用管道AppControllerAppController会在DatabaseModule解决之前得到解决。如果您要在 中使用管道,则可以在管道中forwardRef()注入。这里的好习惯是在功能模块中提供功能控制器。DatabaseServiceAppController

export const FileExistPipe: (filePath: string) => PipeTransform = memoize(
  createFileExistPipe
);

function createFileExistPipe(filePath: string): Type<PipeTransform> {
  class MixinFileExistPipe implements PipeTransform {
    constructor(
      // use forwardRef here
      @Inject(forwardRef(() => DatabaseService)) private db: DatabaseService 
    ) {
      console.log(db);
    }

    async transform(value: ITranscodeRequest, metadata: ArgumentMetadata) {
      console.log(filePath, this.db);
      const doesExist = await this.db.checkFileExists(filePath);
      if (!doesExist) throw new BadRequestException();
      return value;
    }
  }

  return mixin(MixinFileExistPipe);
}
Run Code Online (Sandbox Code Playgroud)

您可以通过 来实现这一点Mixin。您可以导出一个返回此类的工厂函数,而不是导出一个injectable类。

export const FileExistPipe: (filePath: string) => PipeTransform = memoize(createFileExistPipe);

function createFileExistPipe(filePath: string) {
    class MixinFileExistPipe implements PipeTransform {
        constructor(private db: DatabaseService) {}
        ...
    }

    return mixin(MixinFileExistPipe);
}
Run Code Online (Sandbox Code Playgroud)
  1. memoize只是一个简单的函数,用于缓存创建的 mixin-pipe 与filePath. 因此,对于每个filePath,您只有该管道的一个版本。
  2. mixin是一个辅助函数,从中导入nestjs/common将包装该类MixinFileExistPipe并使 DI 容器可用(因此DatabaseService可以注入)。

用法:

@Controller('transcode')
export class TranscodeController {

@Post()
async transcode (
    // notice, there's no "new"
    @Body(FileExistsPipe('input')) transcodeRequest: JobRequest) {
    return await this.videoProducer.addJob(transcodeRequest);
}
Run Code Online (Sandbox Code Playgroud)
  1. 注入 MongoDB 连接的 mixin 防护 注入 MongoDB 连接的 mixin 防护
  2. 控制台显示正在记录的连接 控制台显示正在记录的连接