I am trying to inject a dependency to an exception filter.
Here is my dependency:
@Injectable()
export class SmsService {
constructor() {}
async create() {
console.log('sms created');
}
}
And its module:
@Module({
providers: [SmsService],
exports: [SmsService],
})
export class SmsModule {}
And my exception filter is here:
@Catch(InternalServerErrorException)
export class InternalServerErrorFilter implements ExceptionFilter {
@Inject(SmsService)
private readonly smsService: SmsService;
async catch(exception: InternalServerErrorException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
// smsService is undefined so create property is undefined
await this.smsService.create();
response.status(exception.getStatus()).send({
message: 'Something went wrong our side.',
statusCode: exception.getStatus(),
});
}
}
My app module :
@Module({
imports: [SmsModule, MailsModule],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_FILTER,
useClass: InternalServerErrorFilter,
},
],
})
export class AppModule {}
My main.ts file :
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new InternalServerErrorFilter());
await app.listen(3000);
}
bootstrap();
Finally my app service is here.
@Injectable()
export class AppService {
getHello(): string {
throw new InternalServerErrorException();
}
}
It just throws internal server error exception for executing internal server error filter.
When I send a request to http://localhost:3000 it throws an error like below:
/* await this.smsService.create();
^
TypeError: Cannot read properties of undefined (reading 'create')
*/
My application starts successfully so it seems like no dependency error.
CodePudding user response:
If I recall, enhancers bound by useGlobal*()
have precedence over APP_*
providers (need to double check that). By using new
you are in charge of setting everything that that class instance will need, regardless if it has @Inject()
decorators on properties or in the constructor or not. The @Inject()
just sets metadata that Nest can read so it knows what to set during class instantiation. So, when you pass new InternalServerErrorFilter()
and don't ever set smsService
, you get an error at runtime because that service is never defined, only declared.
If you're going to use global enhancers, I'd highly suggest keeping just one global enhancer binding type, and would even more highly suggest just using the APP_*
bindings because they're easier to keep inline with your application and your e2e tests, plus Nest can do DI on enahncers bound via APP_*