#onModuleInit only called for one controller

33 messages · Page 1 of 1 (latest)

placid karma
#

I'm splitting a module into two controllers and im having issue with onModuleInit being called:

@UseGuards(AuthGuard, AclGuard)
@ApiTags('scripts')
@Controller('project/:project/scripts')
export class ProjectScriptController implements OnModuleInit {
  private scriptService: script_service.ScriptService;

  constructor(
    @Inject('SCRIPT_SERVICE') private readonly client: ClientGrpc,
    private readonly projectService: ProjectService,
  ) {}

  onModuleInit() {
    this.scriptService =
      this.client.getService<script_service.ScriptService>('ScriptService');
  }

and ```ts
@UseGuards(AuthGuard, AclGuard)
@ApiTags('scripts')
@Controller('script')
export class ScriptsController implements OnModuleInit {
private scriptService: script_service.ScriptService;

constructor(
@Inject('SCRIPT_SERVICE') private readonly client: ClientGrpc,
private readonly projectService: ProjectService,
) {}

onModuleInit() {
this.scriptService =
this.client.getService<script_service.ScriptService>('ScriptService');
}

only one is called
warped oxide
#

does ScriptsController's constructor is being called?

placid karma
#

but theyre both in the controller section

warped oxide
#

then you know why that method is not being called neither

#

My bet is that your controller is using some request-scoped provider. So it is being initialized upon requests. And, as per the docs, such providers can’t use those hooks

#

You can use the NEST_DEBUG=true env var to find that out

placid karma
#

I am seeing it in logs

#
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceWrapper] EntityPipe introspected as request-scoped                                                         
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceWrapper] AclController introspected as request-scoped                                                      
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceWrapper] EntityPipe introspected as request-scoped                                                         
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceWrapper] ProjectController introspected as request-scoped                                                  
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceWrapper] EntityPipe introspected as request-scoped                                                         
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceWrapper] ProjectScriptController introspected as request-scoped
#
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceLoader] UsersModule dependencies initialized +0ms
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceLoader] AclModule dependencies initialized +0ms
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceLoader] ProjectModule dependencies initialized +0ms
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InstanceLoader] ScriptModule dependencies initialized +0ms
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InjectorLogger] Resolving dependency MikroORM in the MikroOrmMiddleware provider 
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InjectorLogger] Looking for MikroORM in MikroOrmCoreModule
[Nest] 1791315  - 08/19/2023, 11:09:17 AM     LOG [InjectorLogger] Found MikroORM in MikroOrmCoreModule

dont see it here

#

This is the module def btw:

#
@Module({
  imports: [
    AuthModule,
    AclModule,
    ProjectModule,
    MikroOrmModule.forFeature([Projects, Resources]),
    ClientsModule.registerAsync(
      grpcClient(
        'SCRIPT_SERVICE',
        'script_service',
        [
          'google/protobuf/empty.proto',
          `${protoBasePath}/shared/bundle.proto`,
          `${protoBasePath}/script_service.proto`,
        ],
        'externalServices.scriptServiceUri',
      ),
    ),
  ],
  controllers: [
    ScriptsController,
    ProjectScriptController,
    RevisionsController,
  ],
})
export class ScriptModule {}

and ```ts
export const grpcClient = (
name: string,
packageName: string,
protoPaths: string[],
configValue: string,
): ClientsModuleAsyncOptions => [
{
name: name,
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
transport: Transport.GRPC,
options: {
url: configService.get<string>(configValue),
maxReceiveMessageLength: Number.MAX_SAFE_INTEGER,
package: packageName,
protoPath: protoPaths,
},
}),
},
];

warped oxide
#

And that module doesn’t appears in the initialization logs, right?

placid karma
#

ProjectScriptController doesn't get initialized. For some reason ProjectController does

#

Despite the fact that they are the same other than the methods

warped oxide
#

other than that, if the module is being reached by the root module, there is no reason to onModuleInit not being called (in a standard app)

placid karma
warped oxide
#

It is requested-scoped

placid karma
#

The only request scoped things in the controller are param decorators for methods

warped oxide
#

What about that EntityPipe
It is as well

#

If your provider/controller depends on it, nest cannot initialize it for obvious reasons

#

If you could share your app or a minimum repro, we can help you out. I don’t think there is much to do by now

placid karma
#

That is interesting actually. EntityPipe is only used in project controller

warped oxide
#

And yeah, request scoped can be hard to grasp. That’s why I avoid it

placid karma
#
/**
 * Pipe to convert a primary key to the respective entity.
 * @param type of the entity
 * @returns entity.
 */
export const EntityPipe = <T extends object>(type: EntityName<T>) => {
  @Injectable({ scope: Scope.REQUEST })
  class EntityPipe<T extends object> implements PipeTransform {
    constructor(readonly em: EntityManager) {}

    async transform(value: any): Promise<T> {
      const entity = await this.em.findOneOrFail(type, value);
      return entity as unknown as T;
    }
  }

  return EntityPipe;
};

/**
 * Shorthand for {@link EntityPipe} that assumes its a {@link Param}.
 * @param paramName name of parameter in url string
 * @param entity type of entity
 * @returns entity
 */
export const EntityParam = <T extends object>(
  paramName: string,
  entity: EntityName<T>,
) => Param(paramName, EntityPipe(entity));

#

It transforms an ID to an entity param

warped oxide
warped oxide
placid karma
#

It works without entitypipe

#

hm