如何在NestJS自定义带参Transform Pipe中实现依赖注入?
解决NestJS自定义带参Pipe注入TypeOrm DataSource的问题
直接通过new创建Pipe实例会脱离Nest的DI容器管理,导致无法自动注入DataSource。以下是可行的解决方案:
方法:结合自定义装饰器+DI管理的Pipe
1. 创建元数据装饰器
用来传递需要验证的实体类,并将其存储到参数的元数据中:
import { SetMetadata } from '@nestjs/common'; // 定义元数据键 const VALIDATE_ENTITY_KEY = 'validate_target_entity'; // 自定义装饰器,接收实体类作为参数 export const ValidateEntityExists = (entity: Function) => SetMetadata(VALIDATE_ENTITY_KEY, entity);
2. 修改Pipe实现
让Pipe通过Reflector读取元数据,同时注入DataSource进行查询验证:
import { Injectable, PipeTransform, NotFoundException, ArgumentMetadata, Reflector } from '@nestjs/common'; import { DataSource } from 'typeorm'; @Injectable() export class EntityIdValidationPipe implements PipeTransform { constructor( private readonly dataSource: DataSource, private readonly reflector: Reflector, ) {} async transform(id: string, metadata: ArgumentMetadata): Promise<string> { // 从元数据中获取目标实体类 const entityClass = this.reflector.get<Function>( VALIDATE_ENTITY_KEY, metadata.context ); if (!entityClass) { throw new Error('请通过@ValidateEntityExists指定要验证的实体类'); } // 验证实体是否存在 const exists = await this.dataSource .getRepository(entityClass) .existsBy({ id }); if (!exists) { throw new NotFoundException(`不存在ID为${id}的${entityClass.name}实体`); } return id; } }
3. 在控制器中使用
将装饰器和Pipe结合,替代直接new的方式:
import { Post, Param } from '@nestjs/common'; import { ParseUUIDPipe } from '@nestjs/common'; import { EntityIdValidationPipe } from './entity-id-validation.pipe'; import { ValidateEntityExists } from './validate-entity-exists.decorator'; @Post('track/:id') addTrack( @Param('id', ParseUUIDPipe, EntityIdValidationPipe) @ValidateEntityExists(Track) // 指定要验证的实体类 id: string, ) { return this.favsService.addTrack(id); }
4. 注册Pipe到模块
确保Pipe被加入到模块的providers中,让DI容器管理其生命周期:
import { Module } from '@nestjs/common'; import { EntityIdValidationPipe } from './entity-id-validation.pipe'; @Module({ providers: [EntityIdValidationPipe], }) export class YourModule {}
优化:组合装饰器简化代码
可以封装一个组合装饰器,将Param、Pipe和实体验证装饰器合并,减少重复代码:
import { applyDecorators, Param } from '@nestjs/common'; import { ParseUUIDPipe } from '@nestjs/common'; import { EntityIdValidationPipe } from './entity-id-validation.pipe'; import { ValidateEntityExists } from './validate-entity-exists.decorator'; export const ParamEntityId = (paramName: string, entity: Function) => { return applyDecorators( Param(paramName, ParseUUIDPipe, EntityIdValidationPipe), ValidateEntityExists(entity), ); };
使用时更简洁:
@Post('track/:id') addTrack( @ParamEntityId('id', Track) id: string, ) { return this.favsService.addTrack(id); }
内容的提问来源于stack exchange,提问作者Max Green
相关产品推荐
相关产品推荐

