Modules in NestJS - javascript

Can someone tell me why i have this error:
[Nest] 556 - 2020-06-10 18:52:55 [ExceptionHandler] Nest can't resolve dependencies of the JwtService (?). Please make sure that the argument JWT_MODULE_OPTIONS at index [0] is available in the JwtModule context.
Potential solutions:
- If JWT_MODULE_OPTIONS is a provider, is it part of the current JwtModule?
- If JWT_MODULE_OPTIONS is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing JWT_MODULE_OPTIONS */ ]
})
my modules:
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt'}),
JwtModule.register({
secret: 'topSecret51',
signOptions: {
expiresIn: 3600
},
}),
TypeOrmModule.forFeature([User])
],
controllers: [AuthController],
providers: [AuthService, UserService]
})
export class AuthModule {}
#Module({
controllers: [UserController],
providers: [UserService, AuthService],
imports: [AuthModule]
})
export class UserModule {}
#Module({
imports: [
TypeOrmModule.forRoot(typeOrmConfig),
UserModule,
AuthModule
],
})
export class AppModule {}
i try to change in all of them but in all of them my app does not work
thanks for any help
////////////////////////////////////////////////////

If you are using some dependencies of the controller in JwtService, you need to add JWT_MODULE_OPTIONS as provider inside the current AuthModule. Have a look at the nestjs documentation. They have explained on how to register custom providers.

I received this error when I did not correctly import / initialize the JwtModule. The JwtModule should handle the JwtService initialization which this error comes from. I would start there. If you're using the AuthModule in your test environment which by extension needs the JwtModule then you'll need to manually define your JwtModule with something similar:
beforeAll(async () => {
const testingModule: TestingModule = await Test.createTestingModule({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
MongooseModule.forFeature([{ name: 'User', schema: userSchema }]),
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
secret: configService.get('JWT_SECRET'),
signOptions: { expiresIn: '1d' }
})
}),
],

Related

Use defined value in module provider in other Angular module

I would like use provider value defined in other module. Here is example:
app.module.ts
...
import { ThemeModule } from '../shared/modules/theme/theme.module';
...
#NgModule({
declarations: [
RootComponent,
LoginScreenComponent,
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
BrowserAnimationsModule,
AppRoutingModule,
ConfigModule,
ThemeModule,
....
],
providers: [
...
{ provider: "THEME_NAME", useValue: "VALUE" },
],
bootstrap: [RootComponent]
})
export class MDMToolModule {}
theme.module.ts
import { NgModule } from '#angular/core';
import { ThemeService } from './services/ThemeService';
#NgModule({
imports: [],
declarations: [],
providers: [
{provide: "ThemeService", useFactory: (THEME_NAME) => {
return new ThemeService(THEME_NAME)
}},
],
exports: []
})
export class ThemeModule {}
Is there possibility to pass VALUE defied not in module like above example (THEME NAME)?
if you're providing value in root module then it will be available to all other modules too so you can then simply ask for that value using Inject decorator like this:
#Injectable()
export class ThemeService {
constructor(#Inject("THEME_NAME") theme: string) {}
}
otherwise you can import your MDMToolModule inside ThemeModule though judging by the code you provided I'm assuming this MDMToolModule is your root module,
you can also use Injection Token to avoid using those magic strings like this:
const ThemeName = new InjectionToken("token to inject theme name");
and then use it inside theme.module.ts
#NgModule({
providers: [
{ provide: ThemeName, useValue: "DarkKnight" },
ThemeService
]
})
export class ThemeModule {}
theme.service.ts
#Injectable()
export class ThemeService {
constructor(#Inject(ThemeName) theme: string) {}
}

NestJS - JWTModule context dependency

After run my app i get this...
[Nest] 5608 - 01.01.2021, 18:12:05 [ExceptionHandler] Nest can't resolve dependencies of the JwtService (?). Please make sure that the argument JWT_MODULE_OPTIONS at index [0] is available in the JwtModule context.
Potential solutions:
- If JWT_MODULE_OPTIONS is a provider, is it part of the current JwtModule?
- If JWT_MODULE_OPTIONS is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing JWT_MODULE_OPTIONS */ ]
})
can someone tell me what i have wrong with my code?
#Module({
imports: [TypeOrmModule.forFeature([User]),
JwtModule.register({
secretOrPrivateKey: 'secret12356789'
})
],
providers: [UserService]
})
export class AuthModule { }
#Module({
imports: [
TypeOrmModule.forRoot({
//
}),
AuthModule,
UserModule,
JwtModule
],
controllers: [AppController, UserController, AuthController ],
providers: [AppService, UserService, AuthService ],
})
export class AppModule {}
thanks for any help
///////////////////////////////////////////////////////////////
In your AppModule you have the JwtModule imported but adding no options to it. This is what's causing the issue. As you already have the JwtModule registered in the AuthModule, this probably isn't what you're meaning to do.
You have the UserService registered in at least two places (AuthModule and AppModule), you're probably meaning to add the UserService to the exports of UserModule and then add the UserModule to the imports array of the module where you need the UserService.
TL;DR See, copy/paste examples.
Recently had the same issue.
As Nest.JS recommends the JwtModule could be declared in an authorization module: https://docs.nestjs.com/security/authentication. And, yes, it should be declared once with all its settings. The topic message could come from a multiple declaration (some of them has no JWT_MODULE_OPTIONS). Can wrap Jay's response with a prepared working example.
So the auth module should look like:
//./authorization/authorization.module.ts
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { AuthorizationController } from './authorization.controller';
import { AuthorizationService } from './authorization.service';
#Module({
imports: [
...
JwtModule.register({
secret: process.env.ACCESS_TOKEN_SECRET || 'SOME_SECURE_SECRET_jU^7',
signOptions: {
expiresIn: process.env.TOKEN_EXPIRATION_TIME || '24h',
}
}),
....
],
controllers: [AuthorizationController],
providers: [AuthorizationService],
exports: [AuthorizationService, JwtModule]//<--here exports JwtModule
//as a part of AuthorizationModule
})
export class AuthorizationModule {};
Then your AppModule will inject the exported JwtModule from AuthorizationModule in this way.
//./app.module.js
import { Module } from '#nestjs/common';
import { AuthorizationModule } from './authorization/authorization.module';
#Module({
imports: [
...
AuthorizationModule, //<-- here injects the set up JwtModule
//NB! No additional injections required!
...
],
...
})
export class AppModule {};
Hope, this will help. ;)

Nest can't resolve dependencies of the UserService

I´m having this error
Nest can't resolve dependencies of the UserService (?, SettingsService). Please make sure that the argument UserModel at index [0] is available in the AuthModule context.
Potential solutions:
- If UserModel is a provider, is it part of the current AuthModule?
- If UserModel is exported from a separate #Module, is that module imported within AuthModule?
#Module({
imports: [ /* the Module containing UserModel */ ]
})
auth.module.ts
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: config.auth.secret,
signOptions: {
expiresIn: config.auth.expiresIn,
},
}),
UserModule,
SettingsModule,
],
controllers: [AuthController],
providers: [
AuthService,
JwtStrategy,
LocalStrategy,
UserService,
SettingsService,
Logger,
... other services,
],
exports: [PassportModule, AuthService],
})
export class AuthModule {}
user.module.ts
#Module({
imports: [
MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
SettingsModule,
],
controllers: [UserController],
providers: [UserService],
exports: [UserService],
})
export class UserModule {}
app.module.ts
#Module({
imports: [
AuthModule,
UserModule,
SettingsModule,
MongooseModule.forRoot(config.db.url),
WinstonModule.forRoot({
level: config.logger.debug.level,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
user.service.ts
#Injectable()
export class UserService {
constructor(#InjectModel('User') private readonly userModel: Model<User>,
private readonly settingsService: SettingsService) {}
public async create(user: any): Promise<UserDto> {
...
}
I tried everything and can't find the issue, everything seems correct, i even checked every google page results to try to find it but i'm stuck.
The error tells me that i need to import UserModel into AuthModule, but it's already there, i tried to delete every single user model, or the AuthModule and mix them into everything and it still doesnt work, i know i have to export UserService to AuthModule, but can't find the correct way.
You are providing the UserService in your AuthModule. However, it should only be in your UserModule. In the AuthModule, the UserModel is unknown.
Double-check your module imports:
#Module({
imports: [
MongooseModule.forFeature([
{ name: 'User', schema: UserSchema }
]),
...
],
...
})
export class XModule {}
And look for silly mistakes! because even if you pass schema and schema name instead of each other, there will be no type errors! The general Nest can't resolve dependencies will be all you get for so many mistakes that are probable here...

HttpInterceptor provided in Angular library is not working from Angular app

I am developing an Angular library where there is an authentication module that provides an HttpInterceptor. The main idea is to have this interceptor working automatically in any app that imports this authentication module without having to do any extra setup at it.
What I have so far is the following:
AuthenticationModule
#NgModule({
imports: [ConcreteAuthModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
]
})
export class AuthenticationModule {
static forRoot(config: AuthConfig): ModuleWithProviders {
return {
ngModule: AuthenticationModule,
providers: [
{
provide: AUTH_CONFIG,
useValue: config
}
]
};
}
}
ConcreteAuthModule
#NgModule({
imports: [ThirdPartyLibModule],
providers: [
{
provide: AuthenticationService,
useClass: ConcreteAuthService
}
]
})
export class ConcreteAuthModule { }
BearerInterceptor
#Injectable()
export class BearerInterceptor implements HttpInterceptor {
constructor(private authService: AuthenticationService) { }
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const headers: any = {};
if (this.authService.isUserAuthenticated()) {
headers.Authorization = `Bearer ${this.singleSignOnService.getUserToken()}`;
}
const authReq = req.clone({ setHeaders: headers });
return next.handle(authReq);
}
}
And from a test Angular app I am importing this module the following way at the AppModule:
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
I checked how some third party libraries did this, also came across a couple of Stack Overflow questions that discussed about this and they all suggested having an Angular module created (I already have it: AuthenticationModule), then provide the http-interceptor on it (already have it too) and finally importing this module from an Angular app (also did this).
But still, none of the http requests in my app are being intercepted.
Tried importing the BearerInterceptor directly from my test app and providing it on the AppModule like this:
import { BearerInterceptor } from 'my-lib':
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
And that works! But this workaround is not what I am looking for...
You're very close to a working solution.
The key is to look at how the module is being imported by the AppModule.
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
That is how the AuthenticationModule is imported by the AppModule, but that NgModule does not provide the HTTP_INTERCEPTORS.
You've provided the token in the #NgModule() decorator, but that module is not being used by your application. It's the module defined by the forRoot() function.
Move the declaration of the HTTP_INTERCEPTORS to the forRoot() function.
Try this instead:
#NgModule({
imports: [ConcreteAuthModule]
})
export class AuthenticationModule {
static forRoot(config: AuthConfig): ModuleWithProviders {
return {
ngModule: AuthenticationModule,
providers: [
{
provide: AUTH_CONFIG,
useValue: config
}, {
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
]
};
}
}
The problem was because I was installing the library locally for testing purposes like the following:
$ npm i --save my-lib_path/dist/my-lib
After I published it and installed it from the npm registry it worked fine:
$ npm i --save my-lib

Cannot match any routes. Error in angular?

I made a simple app which is running correctly.
Now I am trying to write test cases of that application, so I tried with routing.
stackblitz
My routing code is this
Main module:
export const routes: Routes = [
{ path: '', redirectTo: '/users', pathMatch: 'full' },
];
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
UserModule,
HttpClientModule,
RouterModule.forRoot(routes)
],
Feature module:
const routes: Routes = [
{path: 'users', component: ListingComponent}
];
#NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes)
],
declarations: [ListingComponent]
})
Code
I try to run my spec but I am getting above error
describe('Initial navigation', () => {
it('default route redirects to home (async)', fakeAsync(() => {
router.initialNavigation(); // triggers default
fixture.detectChanges();
tick();
console.log('==================');
console.log(location.path());
// fixture.whenStable().then(() => {
expect(location.path()).toBe('/users');
// })
}));
});
If you import UserModule to the spec, this resolves the error. As AppModule modules imports UserModule to register user feature/module routes, it must also be imported in the spec to ensure it's route registrations are available in the spec as well.
The need for this is implied at a basic level in the documentation Testing: Import a feature module.
//setup
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
UserModule, // import module
RouterTestingModule.withRoutes(routes)],
declarations: [
TestComponent,
]
});
fixture = TestBed.createComponent(TestComponent);
router = TestBed.get(Router);
location = TestBed.get(Location);
});
Here is an updated StackBlitz demonstrating the functionality (test passing with no error).

Categories