Search code examples
node.jstypescriptnestjstypeorm

NestJS - Cannot inject a service into a subscriber


I have a subscriber for NestJS to listen to any create, update or delete events (TypeORM). When one of these events is fired, I'd like to use an injected service in order to create a new revision entry.

However, it seems I cannot get the dependency loaded inside of the subscriber and the service comes back as being undefined

Key files:

  • EntityModificationSubscriber (Subscriber)
  • RevisionEntity (Entity)

app.module.ts

@Module({
  imports: [
      HttpModule,
      TypeOrmModule.forRoot({
          type: (process.env.DB_TYPE as any) || 'postgres',
          host: process.env.DB_HOST || '127.0.0.1',
          port: (process.env.DB_PORT as any) || 5432,
          username: process.env.DB_USER || 'root',
          password: process.env.DB_PASS || '',
          database: process.env.DB_NAME || 'test',
          entities: [join(__dirname, '**/**.entity{.ts,.js}')],
          synchronize: true,
          logging: 'all',
          logger: 'advanced-console',
          subscribers: [EntityModificationSubscriber],
      }),
      TypeOrmModule.forFeature([
          RevisionEntity,
      ]),
      TerminusModule.forRootAsync({
          // Inject the TypeOrmHealthIndicator provided by nestjs/terminus
          inject: [TypeOrmHealthIndicator, MicroserviceHealthIndicator],
          useFactory: (db, msg) => getTerminusOptions(db, msg),
      }),
      GraphQLModule.forRoot({
          debug: true,
          playground: true,
          typePaths: ['./**/*.graphql'],
      }),
  ],
  controllers: [AppController],
  providers: [
      RevisionService,
      EntityModificationSubscriber,
  ],
})

entity_modification_subscriber.ts

import {EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, UpdateEvent} from 'typeorm';
import {RevisionEntity, RevisonEntityStatus} from '../entities/revison.entity';
import {RevisionService} from '../services/revisions.service';
import {Injectable} from '@nestjs/common';

@Injectable()
@EventSubscriber()
export class EntityModificationSubscriber implements EntitySubscriberInterface {

    constructor(private revisionService: RevisionService) {
    }

    // tslint:disable-next-line:no-empty
    afterInsert(event: InsertEvent<any>): Promise<any> | void {
        const revision = new RevisionEntity();

        revision.action = RevisonEntityStatus.Created;
    }

    afterUpdate(event: UpdateEvent<any>): Promise<any> | void {
    }

    // tslint:disable-next-line:no-empty
    afterRemove(event: RemoveEvent<any>) {
        // this.revisionService.createRevisionEntry(revision);
    }
}

Solution

  • The only way I found to inject a dependency into a subscriber using NestJS, was not to register that subscriber in the TypeORM configuration. I subscribe it manually into the TypeORM connection on subscriber's constructor.

    import { EntitySubscriberInterface, EventSubscriber, InsertEvent, RemoveEvent, UpdateEvent, Connection } from 'typeorm';
        import { RevisionEntity, RevisonEntityStatus } from '../entities/revison.entity';
        import { RevisionService } from '../services/revisions.service';
        import { Injectable } from '@nestjs/common';
    
        @Injectable()
        @EventSubscriber()
        export class EntityModificationSubscriber implements EntitySubscriberInterface {
    
            constructor(private readonly connection: Connection, private readonly revisionService: RevisionService) {
                connection.subscribers.push(this); // <---- THIS 
            }
    
            // tslint:disable-next-line:no-empty
            afterInsert(event: InsertEvent<any>): Promise<any> | void {
                const revision = new RevisionEntity();
    
                revision.action = RevisonEntityStatus.Created;
    
                //this.revisionService <- should be working!
            }
    
            afterUpdate(event: UpdateEvent<any>): Promise<any> | void {
            }
    
            // tslint:disable-next-line:no-empty
            afterRemove(event: RemoveEvent<any>) {
                // this.revisionService.createRevisionEntry(revision);
            }
        }
    

    Then in your app.module on the TypeORM module configuration (TypeOrmModule.forRoot). Remove the line:

    subscribers: [EntityModificationSubscriber],
    

    It solved to me, hope it help others. You can find discussions about that in some NestJS issues/pull requests.

    https://github.com/nestjs/typeorm/issues/85

    https://github.com/nestjs/typeorm/pull/27