0

I want to create a NestJS module I will host on my Verdaccio repository and reuse it into multiple projects, specially into guards. This module use the configService of the app where it is imported as a dependency. But when I import it into the app, I have dependency problems. I don't understand what's happening. Can someone help me to understand and solve this problem ?

First, the module files: myModule.module.ts

import { Module } from '@nestjs/common';
import { MyService } from './myModule.service';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [ConfigModule],
  providers: [MyService,ConfigService],
  exports: [MyService],
})
export class MyModule {}

myModule.service.ts

import { Inject, Injectable, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";

@Injectable()
export class OIDCService {

    private readonly logger:Logger;

    constructor(@Inject("ConfigService") private readonly configService:ConfigService){
        this.logger = new Logger("MyService");
    }

   // ...
    myMethod(){
        const param = this.configService.get("param");
    }
}

Then, the app files:

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule,ConfigService } from '@nestjs/config';
import configValidator from './config/config.validator';
import { MyModule, myService } from 'myModule';
import configSchema from './config/config.schema';

@Module({
  imports: [ConfigModule.forRoot({
    isGlobal: true,
    validationSchema: configValidator,
    cache: true,
    load:[configSchema]
  }),ConfigModule],
  controllers: [AppController],
  providers: [ConfigService,AppService,MyModule,MyService,ConfigModule],
})
export class AppModule {}

myGuard.ts

import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
import { Request } from 'express';
import { Observable } from 'rxjs';
import { MyService } from 'myModule';

@Injectable()
export class MyGuard implements CanActivate {
  constructor(@Inject() private readonly myService:MyService){}

  canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
    //...
    return (
      this.myService.myMethod()
      .then(//...)
    )
  }
}

This is the nest error : Nest can't resolve dependencies of the OIDCModule (?). Please make sure that the argument ConfigModule at index [0] is available in the AppModule context.

Thanks !

Wapax
  • 37
  • 8

1 Answers1

1
  1. Modules never go in the providers array. period. They go in the imports array. Read that again. Good.

  2. Never add a provider from a module that you are already importing to the current module's providers array. Every time you put a provider in the providers array, you tell Nest to create a new instance of that provider. In this case, your MyMoudle shouldn't have ConfigService in the providers array, it's already available because the ConfigModule is in the imports array and it exports the ConfigService.

  3. Don't use a class's name string as the injection token (e.g. @Inject('ConfigService')) This worked back on Nest v7, but in v8 there was a change that made the class reference the injection token rather than the name alone.

    • If you are already using the class type as the type in the constructor and the class has a decorator at the class level (e.g. @Injectable()) or a parameter decorator in the constructor, then you don't need to @Inject() the class type if the class is a provided Nest provider (i.e. it's in a providers array). Typescript will emit the metadata for the parameters automatically and Nest will read that to know what to inject.
  1. If you need to use @Inject(), don't do it without a parameter
Jay McDoniel
  • 57,339
  • 7
  • 135
  • 147