NestJS - Export Custom Factory Provider (useFactory) - nestjs

I have created a custom provider in one of my modules.
I need to export that custom provider to make it available in other modules and I'm having trouble doing so. I do not know what to put in the exports array.
Below is my custom provider.
#Module({
imports: [TypeOrmModule.forFeature([TypeOrmUser])],
providers: [
UserMapper,
UserService,
{
provide: getRepositoryToken(TypeOrmUser),
inject: [getDataSourceToken()],
useFactory(dataSource: DataSource) {
return dataSource.getRepository(TypeOrmUser).extend(userRepositoryImpl);
},
},
],
exports: [UserService, 'what to put here to export custom user repository?'],
})
export class UsersModule {}
Thank you for your help.

To export a custom provider, all that is needed to be added to the exports array is the provider's injection token.
In this case, that's getRepositoryToken(TypeOrmUser)

You can export it either with token name, or with the whole provider object. In your case it would be something like this:
exports: [UserService, getRepositoryToken(TypeOrmUser)],
or:
const customProvider = {
provide: getRepositoryToken(TypeOrmUser),
inject: [getDataSourceToken()],
useFactory(dataSource: DataSource) {
return dataSource.getRepository(TypeOrmUser).extend(userRepositoryImpl);
},
};
#Module({
imports: [TypeOrmModule.forFeature([TypeOrmUser])],
providers: [
UserMapper,
UserService,
customProvider,
],
exports: [UserService, customProvider],
})

Related

Nest can't resolve dependencies of the DiscoveryService (?). Please make sure that the argument ModulesContainer at index [0] is available in

In a NestJs project, I created a module that uses, DiscoveryService in the services. It working fine. I wanted to create a nest library from that module. I followed this nestJs documentation then I am getting the below error. I tried both adding ModulesContainer in to my module imports and providers. nothing helped.
[Nest] 65775 - 10/12/2022, 11:55:03 AM ERROR [ExceptionHandler] Nest can't resolve dependencies of the DiscoveryService (?). Please make sure that the argument ModulesContainer at index [0] is available in the DiscoveryModule context.
Error log
Potential solutions:
If ModulesContainer is a provider, is it part of the current DiscoveryModule?
If ModulesContainer is exported from a separate #Module, is that module imported within DiscoveryModule? #Module({
imports: [ /* the Module containing ModulesContainer */ ] })
Error: Nest can't resolve dependencies of the DiscoveryService (?).
Please make sure that the argument ModulesContainer at index [0] is
available in the DiscoveryModule context.
library
import { DiscoveryService } from '#nestjs/core';
#Injectable()
export class EventPublishingService {
private readonly logger = new Logger(EventPublishingService.name);
private readonly publishingEventProviders;
constructor(
private discoveryService: DiscoveryService
) {
this.publishingEventProviders = this.discoveryService
.getProviders()
.filter(
({ metatype }) =>
metatype && Reflect.getMetadata(PUBLISHABLE_METADATA, metatype),
);
}
}
#Global()
#Module({
imports: [DiscoveryModule, HttpModule, ConfigModule],
providers: [
EventRegistrationService,
EventManagerServiceApi,
EventPublishingService],
exports: [EventPublishingService],
})
export class EventManagerModule {}
app module
#Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
cache: true,
load: [configuration],
}),
ScheduleModule.forRoot(),
MongooseModule.forRootAsync({
imports: [DataVaultManagerModule],
inject: [DataVaultManager],
useClass: MongooseConfigService,
}),
ParticipantsModule,
StudiesModule,
HealthModule,
EventManagerModule,
UsersModule,
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_PIPE,
useClass: ZodValidationPipe,
},
],
})
export class AppModule {}
Try changing constructor from EventPublishingService class like below:
constructor(
#Inject(DiscoveryService) private discoveryService: DiscoveryService
)

Dependency Injection in Nestjs Service classes

I have two modules whose services are dependent on one another.
// organization.module.ts
//...imports
#Module({
imports: [
forwardRef(() => EmployeeModule),
TypeOrmModule.forFeature([
OrganizationRepository,
Employee
])
],
controllers: [OrganizationController],
providers: [
OrganizationService
]
})
export class OrganizationModule {}
Organization Service*
#Injectable()
export class OrganizationService {
constructor(
#InjectRepository(OrganizationRepository)
private orgRepository: OrganizationRepository,
#InjectRepository(Employee)
private employeeRepsoitory: Repository<Employee>,
private readonly employeeService: EmployeeService,
){}
//...
}
Then i have my employee module and service
employee.module.ts
#Module({
imports: [
forwardRef(() => OrganizationModule),
//...
]
controllers: [EmployeeController],
providers: [EmployeeService, JwtStrategy],
exports: [EmployeeService],
})
export class EmployeeModule {}
and then i have my employee service
employee.service.ts
#Injectable()
export class EmployeeService {
constructor(
private readonly organizationService: OrganizationService
) {}
Now i am getting this DI error and i dont know what is going wrong here. I have tried
#Inject(forwardRef(() => Service)) but didnt seem to work.
My app.module.ts looks like
//...
#Module({
imports: [
OrganizationModule,
],
controllers: [AppController],
providers: [
AppService,
],
})
export class AppModule {}
What am i doing wrong?
You are missing an exports in OrganizationModule.
Add to OrganizationModule:
exports: [OrganizationService]

How to override provider for tests in NestJs and not create transitive dependencies that are not needed?

I am writing end-to-end tests in NestJs and using the "overrideProvider" function to setup test versions of various services (e.g. services that require database connections). I noticed though that even when I do this, the original implementation that injects the real database is still instantiated.
Is there a way to tell Nest to not create transitive dependencies that are overridden?
For example, I have a test that starts like:
...
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [ServiceModule],
})
// Works if I uncomment these lines:
// .overrideProvider('Database')
// .useValue(new TestDatabase())
.overrideProvider('ServiceUsingDatabase')
.useValue(new TestService())
.compile();
...
Where the module setup is like:
import { Inject, Injectable, Module } from '#nestjs/common';
interface Database {}
#Injectable()
class ProductionDatabase implements Database {
constructor() {
throw('Cannot create a production database.');
}
}
#Injectable()
export class TestDatabase implements Database {
constructor() {
console.log('Creating the test database.');
}
}
#Module({
providers: [
{
provide: 'Database',
useClass: ProductionDatabase
}
],
exports: ['Database']
})
class DatabaseModule {}
interface Service {}
#Injectable()
class ProductionService implements Service {
constructor(#Inject('Database') private readonly database: Database) {}
}
#Injectable()
export class TestService implements Service {
// Test implementation of the service does not Inject anything.
}
#Module({
imports: [DatabaseModule],
providers: [
{
provide: 'ServiceUsingDatabase',
useClass: ProductionService
}
],
})
export class ServiceModule {}
But, the DI system is still seeming to try and instantiate ProductionDatabase. If I explicitly override the provider for the 'Database' it works, but I'd like to avoid having to explicitly list all transitive dependencies as such.
I ended up deciding to make a "Test" Module for every Module e.g.:
import { Inject, Injectable, Module } from '#nestjs/common';
interface Database {}
#Injectable()
class ProductionDatabase implements Database {
}
#Injectable()
export class TestDatabase implements Database {
}
#Module({
providers: [
{
provide: 'Database',
useClass: ProductionDatabase
}
],
exports: ['Database']
})
class DatabaseModule {}
#Module({
providers: [
{
provide: 'Database',
useClass: TestDatabase
}
],
exports: ['Database']
})
class TestDatabaseModule {}
interface Service {}
#Injectable()
class ProductionService implements Service {
constructor(#Inject('Database') private readonly database: Database) {}
}
#Injectable()
export class TestService implements Service {
}
#Module({
imports: [DatabaseModule],
providers: [
{
provide: 'ServiceUsingDatabase',
useClass: ProductionService
}
],
})
export class ServiceModule {}
#Module({
providers: [
{
provide: 'ServiceUsingDatabase',
useClass: TestService
}
],
})
export class TestServiceModule {}
etc... Though it turned out after some refactorings that the "Test" module wasn't needed as some Modules became pure business logic.

Dynamic ConfigModule cannot Inject in custom JwtModule

I created my Dynamic configModule to extract environment variables from a different path. It extracts from an yml file. Everything works properly if a add in some module. Here is my ConfigModule:
import { DynamicModule } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import { EnvConfigService } from './env.config.service';
export class EnvConfigModule {
/**
* Create an static function to call directly from the class without instantiation
* #param options: Our config module attributes or properties
* #returns DynamicModule
*/
static register(options): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: 'CONFIG_OPTIONS',
useValue: options,
},
EnvConfigService,
],
exports: [EnvConfigService],
};
}
}
Now when I want to add that configuration in the new custom JwtModule, CustomJwtModule:
...
import { EnvConfigModule } from 'src/utils/environment/env.config.module';
import { EnvConfigService } from 'src/utils/environment/env.config.service';
#Module({
imports: [
JwtModule.registerAsync({
imports: [EnvConfigModule],
inject: [EnvConfigService],
useFactory: (configService: EnvConfigService) => {
const base64_pubKey = configService.get(ACCESS_PUBLIC_KEY_NAME);
return {
publicKey: Buffer.from(base64_pubKey, KEY_ENCODING),
signOptions: {
algorithm: ENCRYPTION_ALGORITHM,
},
};
},
}),
],
providers: [
{
provide: JWT_ACCESS_SERVICE,
useExisting: JwtService,
},
],
exports: [JWT_ACCESS_SERVICE],
})
export class JWTAccessModule {}
And here is my error:
Error: Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument EnvConfigService at index [0] is available in the JwtModule context.
I guess, I do get that error because it does not inject properly in JWT module my service.
My app.module.ts is implemented in that way
...
import { EnvConfigModule } from './utils/environment/env.config.module';
#Module({
imports: [
IamModule,
EnvConfigModule.register({
folder: 'config/environment/',
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Ok, it seems I was importing wrongly. It was missing some part of the configuration. Here is the working example of CustomJwtModule:
...
import { EnvConfigModule } from 'src/utils/environment/env.config.module';
import { EnvConfigService } from 'src/utils/environment/env.config.service';
#Module({
imports: [
JwtModule.registerAsync({
imports: [EnvConfigModule.register({
folder: 'config/environment/',
}),
],
inject: [EnvConfigService],
...

NestJs Authentication Circular Dependency

I am fairly new to nestJs. I am trying to implement an authentication process according to nestjs documentation, but I don't want to route the login in the app.controller I want to put it in the users.controller, so the route will be /users/login. However, since the AuthModule already uses the UsersService in my code and the login logic with JWT is in the AuthService. Importing it back to the UsersService create a circular dependency. I need help.
To avoid circular dependancy, in your UsersModule, you need to import your AuthModule with ForwardRef like that :
import ...
#Module( {
imports: [
forwardRef( () => AuthModule ),
],
controllers: [],
providers: [],
exports: []
} )
export class UsersModule {
}
If you haven't already done so, you'll need to export the AuthService in AuthModule :
import ...
#Module( {
imports: [],
controllers: [],
providers: [],
exports: [
AuthService
]
} )
export class AuthModule {
}

Resources