This code is to integrate NestJs on sentry .
**SentryModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
dsn: configService.get<string>('sentry.dsn'),
debug: true,
environment: configService.get<string>('sentry.env'),
logLevels: ['error'],
}),
inject: [ConfigService],
})
],
providers: [
{
provide: APP_INTERCEPTOR,
useValue: new SentryInterceptor(),
},
],
controllers: [AppController],
})
export class AppModule {}**
I need to integrate performance monitoring in NestJs on sentry.
Related
There are plenty of articles showing how to inject providers into dynamic module but all of them only show examples using their exported services, none with middleware. Using the exact same method as used with services for middleware fails. How can I create reusable middleware that requires providers to be injected?
Example middleware, requiring injection of a UserService provider
#Injectable()
export class AuthMiddleware implements NestMiddleware {
constructor(#Inject(USER_SERVICE) private readonly userService: UserService) {
console.log('userService findAll: ', userService.findAll());
}
use(req: any, res: any, next: () => void) {
console.log('AuthMiddleware called!');
next();
}
}
Example module containing the middleware:
#Module({
providers: [AuthService, AuthMiddleware],
imports: [ExtModule],
})
export class AuthModule extends createConfigurableDynamicRootModule<
AuthModule,
AuthModuleOptions
>(AUTH_OPTIONS, {
providers: [
{
provide: AUTH_SECRET,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.secret,
},
{
provide: USER_SERVICE,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.userService,
},
],
controllers: [AuthController],
}) {}
Now importing the module and trying to use the middleware:
#Module({
imports: [
ConfigModule.forRoot(),
AuthModule.forRootAsync(AuthModule, {
imports: [ConfigModule, UserModule],
inject: [ConfigService, UserService],
useFactory: (config: ConfigService, userService: UserService) => {
return {
secret: config.get('AUTH_SECRET_VALUE'),
userService,
};
},
}) as DynamicModule,
UserModule,
],
controllers: [UserController],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
}
Now when initializing the AuthModule dependencies the middleware class is clearly instantiated correctly, the userService.findAll being logged:
userService findAll: []
So far so good, and this works fine for services.
But the problem is that when then actually using the middleware in configure(), the injected context is not used
...\app\node_modules\#nestjs\core\injector\injector.js:193
throw new unknown_dependencies_exception_1.UnknownDependenciesException(wrapper.name, dependencyContext, moduleRef);
^
Error: Nest can't resolve dependencies of the class AuthMiddleware {
constructor(userService) {
this.userService = userService;
console.log('userService findAll: ', userService.findAll());
}
use(req, res, next) {
console.log('AuthMiddleware called!');
next();
}
} (?). Please make sure that the argument Symbol(USER_SERVICE) at index [0] is available in the AppModule context.
I've ended up getting it to work, mostly by re-exporting the injected providers. After trying different combinations, the working one is as follows
Static dependencies (e.g. external libraries) need to be imported and re-exported inside the module decorator
Dynamic dependencies need to be imported and re-exported inside createConfigurableDynamicRootModule
Exporting the Middleware class seems to have no effect in any way
#Module({
providers: [],
imports: [ExtModule],
exports: [ExtModule],
})
export class AuthModule extends createConfigurableDynamicRootModule<
AuthModule,
AuthModuleOptions
>(AUTH_OPTIONS, {
providers: [
{
provide: AUTH_SECRET,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.secret,
},
{
provide: USER_SERVICE,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.userService,
},
],
exports: [
{
provide: AUTH_SECRET,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.secret,
},
{
provide: USER_SERVICE,
inject: [AUTH_OPTIONS],
useFactory: (options: AuthModuleOptions) => options.userService,
},
],
}) {}
I'm new with NestJS and trying to understand the patterns.
I configure ConfigModule to use config set in a specific folder. I want to use that ConfigModule in a submodule but It doesn't work.
I have an app.module
app.module.ts
#Module({
imports: [
ConfigModule.forRoot({
envFilePath: ['.env.local', '.env'],
isGlobal: true,
expandVariables: true,
load: [dbConfiguration, jwtConfiguration],
}),
DatabaseModule,
AuthModule,
UsersModule,
],
controllers: [AppController],
providers: [],
exports: [ConfigModule]
})
export class AppModule {
}
auth.module.ts
#Module({
imports: [
UsersModule,
PassportModule,
ConfigModule,
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secretOrPrivateKey: configService.get('jwt').secret,
signOptions: {
expiresIn: 3600,
},
}),
inject: [ConfigService],
}),
],
providers: [AuthService, JwtStrategy],
exports: [AuthService]
})
export class AuthModule {}
jwt.strategy.ts
import { PassportStrategy } from "#nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";
import {ConfigService} from "#nestjs/config";
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(configService: ConfigService) {
console.log(configService);
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get('jwt').secret,
})
}
async validate(payload: any) {
return {userId: payload.sub, email: payload.email}
}
}
In the constructor, configService is undefined.
I import ConfigModule in auth.module that contain JwtStrategy.
What did I missed?
Missed the #Injectable() in JwtStrategy
Okay so I'm using TYPEORM_ prefixed environment variables to register TypeOrmModule into my app. Then I'm loading entities using .forFeature() like so:
#Module({
imports: [TypeOrmModule.forFeature([Foo])],
controllers: [FooController],
providers: [FooService],
exports: [TypeOrmModule],
})
export class FooModule {}
No matter whether I use forRoot() or forRoot({ autoLoadEntities: true }) in AppModule, I get RepositoryNotFoundError: No repository for "Foo" was found. Looks like this entity is not registered in current "default" connection? error while working with the dev server. Any idea what's going on? My service looks like:
#Injectable()
export class FooService {
constructor(#InjectRepository(Foo) private readonly fooRepository: Repository<Foo>) {}
}
I tried the followings as single and/or combined, still didn't solve the issue.
Put a name in #Entity() decorator.
#Entity('foo')
export class Foo {}
Try forRootAsync().
#Module({
imports: [
TypeOrmModule.forRootAsync({
useFactory: async () =>
Object.assign(await getConnectionOptions(), { autoLoadEntities: true }),
}),
FooModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Pass 'default' to forFeature().
#Module({
imports: [TypeOrmModule.forFeature([Foo], 'default')],
controllers: [FooController],
providers: [FooService],
exports: [TypeOrmModule],
})
export class FooModule {}
Try using entities key in forRoot().
#Module({
imports: [
TypeOrmModule.forRoot({ entities: [Foo] }),
FooModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
try to define connectionName inside getConnectionOptions
example:
#Module({
imports: [
TypeOrmModule.forRootAsync({
useFactory: async () =>
Object.assign(await getConnectionOptions('default'), { autoLoadEntities: true }),
}),
FooModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
How can I create two or multiple instances of a nestjs module? E.g. we would like to have two different instances of the TwilioModule and use different configurations for them.
import { TwilioModule } from 'nestjs-twilio';
#Module({
imports: [
TwilioModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (cfg: ConfigService) => ({
accountSid: cfg.get('TWILIO_ACCOUNT_SID'),
authToken: cfg.get('TWILIO_AUTH_TOKEN'),
}),
inject: [ConfigService],
}),
TwilioModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (cfg: ConfigService) => ({
accountSid: cfg.get('TWILIO_ACCOUNT_SID_2'),
authToken: cfg.get('TWILIO_AUTH_TOKEN_2'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}
Hey for this the package needs to have this feature.
I recommend this.
import { Twilio } from 'twilio';
providers: [
{
provide: 'twilio1',
useFactory: () => {
return new Twilio('ACasd', 'wasdsa');
},
},
{
provide: 'twilio2',
useFactory: () => {
return new Twilio('ACasd', 'wasdsa');
},
},
]
Use the following in the controller or in service
#Inject("twilio1") t1 : Twilio
Example:-
constructor(#Inject('twilo1') t1: Twilio) {}
read more # https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory
I am learning NestJS and I am trying to test a service which incorporates a repository with TypeORM. It compiles fine without errors, but when I run the test it throw an error.
I know it is a test dependency problem but I can't figure it out. I am trying this test:
describe('JokesService', () => {
let service: JokesService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [],
imports: [
TypeOrmModule.forFeature([JokeEntity])
],
}).compile();
service = module.get<JokesService>(JokesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
The module:
#Module({
providers: [JokesService],
imports: [
TypeOrmModule.forFeature([JokeEntity])
],
controllers: [JokesController],
})
export class JokesModule {}
The service:
#Injectable()
export class JokesService {
constructor(
#InjectRepository(JokeEntity)
private readonly jokeRepository: MongoRepository<JokeEntity>
) {}
}
The main module:
#Module({
imports: [
TypeOrmModule.forRoot({
type: 'mongodb',
url: dbUri,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
ssl: true,
useUnifiedTopology: true,
useNewUrlParser: true,
}),
JokesModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
And the error:
Nest cant resolve dependencies of the JokeEntityRepository (?).
Please make sure that the argument Connection at index [0] is available in the TypeOrmModule context.
Potential solutions:
- If Connection is a provider, is it part of the current TypeOrmModule?
- If Connection is exported from a separate #Module, is that module imported within TypeOrmModule?
#Module({
imports: [ /* the Module containing Connection */ ]
})
Can someone tell me what I am missing in the test dependencies? Thank You.
Try to import your JokesModule inside your app.module.
#Module({
imports: [
TypeOrmModule.forRoot({
type: 'mongodb',
url: dbUri,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
ssl: true,
useUnifiedTopology: true,
useNewUrlParser: true,
}),
JokesModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}