I tried to create a dynamic module PermissionModule
like the following:
permTestApp.module.ts
@Module({
imports: [PermissionModule.forRoot({ text: 'abc' })],
providers: [],
controllers: [PermissionTestController],
})
export class PermissionTestAppModule {}
permission.module.ts
import { DynamicModule, Module } from '@nestjs/common'
import { PermissionGuard } from './guard/permission.guard'
@Module({})
export class PermissionModule {
public static forRoot(config: { text: string }): DynamicModule {
return {
module: PermissionModule,
providers: [
{
provide: 'xoxo',
useValue: config.text,
},
PermissionGuard,
],
exports: [PermissionGuard],
}
}
}
permission.guard.ts
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
} from '@nestjs/common'
@Injectable()
export class PermissionGuard implements CanActivate {
constructor(@Inject('xoxo') private readonly config: string) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
console.log(31, this.config)
return true
}
}
AFAIK, 'abc' string must be injected when PermissionGuard
is used.
I tried to test it with the following code.
permission.e2e.spec.ts
beforeAll(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [PermissionTestAppModule],
})
.compile()
app = moduleRef.createNestApplication()
controller = await moduleRef.resolve(PermissionTestController)
await app.init()
})
but it says,
Nest can't resolve dependencies of the PermissionGuard (?). Please make sure that the argument xoxo at index [0] is available in the PermissionTestAppModule context.
Potential solutions:
- Is PermissionTestAppModule a valid NestJS module?
- If xoxo is a provider, is it part of the current PermissionTestAppModule?
- If xoxo is exported from a separate @Module, is that module imported within PermissionTestAppModule?
@Module({
imports: [ /* the Module containing xoxo */ ]
})
What am I doing wrong?
You will need to export the injection token from the module. The reason is that the global context needs to know the existence of that injection token when trying to inject the dependency into a guard, middleware, interceptor, or filter - anything that happens outside the context of your
PermissionModule
.Also, make it global so you won't need to import it into each module. Optional, but depends on your use case.
I suggest using a symbol for injection tokens, and keeping it in a constants file somewhere and importing it wherever you need it, so if that token ever needs to change, you know... DRY.
Hope this helps.