I have a class that is not related to any nest modules. I wanted to import and use my ConfigService inside of this class. Can I do this without adding this class to any module or do I need to have a module in order to use nest generated classes?
Thanks
You can create on class like below
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
#Injectable()
export class AppConfig {
static service: ConfigService;
constructor(service: ConfigService) {
AppConfig.service = service;
}
static get(key: string): any {
return AppConfig.service.get(key);
}
}
add this class as a provider in your root module AppModule,
...
providers: [AppConfig],
...
now once the app is booted, you can use it as following anywhere inside app,
AppConfig.get('database.port');
Hope this helped!
Yep, you can get anything from Nest.js DI container using app.get method.
e.g.
const configService = app.get(ConfigService)
Building on Vinayak Sarawagi's solution, you can even do this inside your custom ConfigModule:
import { Injectable } from '#nestjs/common'
import { ConfigService } from '#nestjs/config'
#Injectable()
export class MyConfigService {
static config: MyConfigService
constructor(private configService: ConfigService) {
MyConfigService.config = this
}
get isDevelopment(): boolean {
return this.configService.get('NODE_ENV') === 'development'
}
}
you can then use whatever private property you have on that service
AppConfig.config.isDevelopment
See the linked answer for details how to export the module globally.
Related
I have a NestJS App and I have a Class where the app generates multiple instances from. Inside that class I need to access a service method but I dont know how to inject a service into a plain class.
This is the service I want to use inside the class "Stream"
import { Injectable } from '#nestjs/common';
import * as technicalindicators from 'technicalindicators';
import { CandleIndex } from 'src/utils/CandleIndex';
import * as ccxt from 'ccxt';
#Injectable()
export class AnalysisService {
async RSI(ohlcv: ccxt.OHLCV[], period: number) {
const close = ohlcv.map((candle) => candle[CandleIndex.CLOSE]);
const result = technicalindicators.rsi({ values: close, period: period });
return result;
}
}
import { AnalysisService } from './analysis.service';
import { Module } from '#nestjs/common';
#Module({
imports: [],
controllers: [],
providers: [AnalysisService],
exports: [AnalysisService],
})
export class AnalysisModule {}
Here is the class I want to get access to the analysis service. The class is a normal typescript class, its not part of any module.
export class Stream {
private exchange: ccxt.Exchange;
private market: ccxt.Market;
private timeframe: string;
private ohlcv_cache: ccxt.OHLCV[];
private createdAt: Date;
private stream;
#Inject(AnalysisService)
private readonly analysisService: AnalysisService;
constructor(exchange: ccxt.Exchange, market: ccxt.Market, timeframe: string) {
this.exchange = exchange;
this.market = market;
this.timeframe = timeframe;
this.createdAt = new Date();
this.initialize();
console.log(this.analysisService);
}
}
When I do this and call a method of the analysis service inside of the Stream class, analysisService is undefined.
As you're calling new Stream() yourself, Nest will do no injection for you. You'd need to either pass the AnalysisService instance yourself, or you'd need to create a setter for that property before running any methods that need the AnalysisService.
I'm trying to create my custom JwtModule. I made JwtModule a dynamic module so that I can provide a private key using dotenv.
jwt.module.ts :
import { DynamicModule, Module } from '#nestjs/common';
import { CONFIG_OPTIONS } from './jwt.constants';
import { JwtModuleOptions } from './jwt.interfaces';
import { JwtService } from './jwt.service';
#Module({})
export class JwtModule {
static forRoot(options: JwtModuleOptions): DynamicModule {
return {
module: JwtModule,
providers: [
{
provide: CONFIG_OPTIONS,
useValue: options,
},
JwtService,
],
exports: [JwtService],
};
}
}
jwt.service.ts :
import { Inject, Injectable } from '#nestjs/common';
import { CONFIG_OPTIONS } from './jwt.constants';
import { JwtModuleOptions } from './jwt.interfaces';
#Injectable()
export class JwtService {
constructor(
#Inject(CONFIG_OPTIONS) private readonly options: JwtModuleOptions,
) {}
// I will do something here
}
users.module.ts :
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { JwtModule } from 'src/jwt/jwt.module';
import { User } from './entities/user.entity';
import { UsersResolver } from './users.resolver';
import { UsersService } from './users.service';
#Module({
imports: [TypeOrmModule.forFeature([User]), JwtModule],
providers: [UsersResolver, UsersService],
})
export class UsersModule {}
users.service.ts :
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { InternalServerErrorOutput } from 'src/common/common.constants';
import { JwtService } from 'src/jwt/jwt.service';
import { Repository } from 'typeorm';
import {
CreateAccountInput,
CreateAccountOutput,
} from './dtos/create-account.dto';
import { User } from './entities/user.entity';
#Injectable()
export class UsersService {
constructor(
#InjectRepository(User)
private readonly userRepository: Repository<User>,
private readonly jwtService: JwtService,
) {}
// I will do something here
}
I imported JwtModule into app.module.ts like this :
JwtModule.forRoot({ privateKey: process.env.JWT_PRIVATE_KEY })
However, when I try to run this application, the console prints an error:
Nest can't resolve dependencies of the UsersService (UserRepository, ?).
Please make sure that the argument JwtService at index [1] is available in the UsersModule context.
Potential solutions:
- If JwtService is a provider, is it part of the current UsersModule?
- If JwtService is exported from a separate #Module, is that module imported within UsersModule?
#Module({
imports: [ /* the Module containing JwtService */ ]
})
Since I exported JwtService and imported JwtModule into UsersModule, so what the error suggests does not help. Using #Global to JwtModule is a simple solution, but as I will not use JwtModule elsewhere, so I would like to know the way without making it global. Any help would be greatly appreciated. Thank you!
Dynamic modules are just that, dynamic. They need to have their configuration/registration methods called when they are about to be made of use. You register the JwtModule in your AppModule, but not in your UserModule, so UserModule doesn't see the returned module with the JwtService exported, it sees a module with no providers and no exports. There's a couple of ways around this,
you can register the JwtModule in the UserModule directly, if you aren't going to re-use this, it might not be a bad idea
you can create a wrapper module tat imports the JwtModule.forRoot() and exports the JwtModule, then you import the wrapper module where you need the JwtModule and get back the configured module each time
this is mostly overkill, but cool to know, you can follow the RxJS Subject approach in this repository that would allow you to do something like JwtMoule.externallyConfigured(0) and get the configuration that was made in AppModule. Again, overkill, but cool
I have an app that receives a service as a dependency on the controller, so far so good, but I would like to find a way to instead of declaring the specific implementation of that service, to be able to "ask" from the controller for the interface that this service implements to decouple of the concrete implementation of that service. How is this done in nest js?
To do this you have to create an injection token for your interface and use the #Inject() decorator with the injection token when injecting your service. Then in your module you can declare which implementation to provide for that injection token.
Below is a simple greeting service interface and our injection token that will be used when registering our service as a provider.
greeting-service.interface.ts
// This will be our injection token.
export const GREETING_SERVICE = 'GREETING SERVICE';
export interface IGreetingService {
greet(name: string): Promise<string>;
}
A basic service that will implements our greeting interface...
professional-greeting.service.ts
import { Injectable } from '#nestjs/common';
import { IGreetingService } from './greeting-service.interface';
#Injectable()
export class ProfessionalGreetingService implements IGreetingService {
public async greet(name: string): Promise<string> {
return `Hello ${name}, how are you today?`;
}
}
And our greeting module where we register our service using the token...
greeting.module.ts
import { Module } from '#nestjs/common';
import { ProfessionalGreetingService } from './services/professional-greeting.service';
import { GREETING_SERVICE } from './services/greeting-service.interface';
import { GreetingController } from './controllers/greeting.controller';
#Module({
providers: [
{
// You can switch useClass to different implementation
useClass: ProfessionalGreetingService,
provide: GREETING_SERVICE
}
],
controllers: [
GreetingController
]
})
export class GreetingModule {}
Now when we inject our service, we can use the #Inject() decorator with our injection token. Whichever implementation you provived to useClass in our GreetingModule will be injected...
greeting.controller.ts
import { Controller, Get, Inject, Query } from '#nestjs/common';
import { GREETING_SERVICE, IGreetingService } from '../services/greeting-service.interface';
#Controller('greeting')
export class GreetingController {
constructor(
#Inject(GREETING_SERVICE)
private readonly _greetingService: IGreetingService
) {}
#Get()
public async getGreeting(#Query('name') name: string): Promise<string> {
return await this._greetingService.greet(name || 'John');
}
}
https://jasonwhite.xyz/posts/2020/10/20/nestjs-dependency-injection-decoupling-services-with-interfaces/
https://github.com/jmw5598/nestjs-di-decoupling-with-interfaces
https://docs.nestjs.com/fundamentals/custom-providers
When I use Custom Repository class without any extension then I run into the error: No repository for "MasterDataRepo" was found. Looks like this entity is not registered in current "default" connection?
#EntityRepository()
export class MasterDataRepo {
constructor(private manager: EntityManager) {
}
getDriveryByTerminal(terminalCode: string):Promise<Driver> {
return this.manager.findOne(Driver, { terminalCode });
}
}
The app works fine if I create repository class after extending Repository<Entity>
#EntityRepository(Driver)
export class MasterDataRepo extends Repository<Driver> {
getDriveryByTerminal(terminalCode: string):Promise<Driver> {
return this.manager.findOne(Driver, { terminalCode });
}
}
My MasterDataModule is:
import { Module } from '#nestjs/common';
import { MasterDataController } from './MasterData.controller';
import { MasterDataService } from './masterData.service';
import { TypeOrmModule } from '#nestjs/typeorm';
import { MasterDataRepo } from './MasterData.Repo';
#Module({
imports: [
TypeOrmModule.forFeature([MasterDataRepo])
],
controllers: [MasterDataController],
providers: [MasterDataService],
})
export class MasterDataModule {}
and AppModule is:
import { Module } from '#nestjs/common';
import { TasksModule } from './tasks/tasks.module';
import { TypeOrmModule } from '#nestjs/typeorm';
import { typeOrmConfig } from './config/typeorm.config';
import { MasterDataModule } from './masterData/MasterData.module';
import { Connection } from 'typeorm';
#Module({
imports: [
TypeOrmModule.forRoot(typeOrmConfig),
TasksModule,
MasterDataModule
],
})
export class AppModule {
constructor(private connection: Connection) {}
}
TypeOrmModule.forFeature([MasterDataRepo])
TypeOrmModule.forFeature accepts array of Entities and your MasterDataRepo is not an entity.
But when you use EntityRepository decorator with the User entity, it will add your User entity to the available entities list(which will be applied to the database connection).
Also extending the Repository class will make your MasterDataRepo as an extended version of an Entity.
https://github.com/typeorm/typeorm/blob/906d97fc8dbf1dba8f4e579a4f5bfead83af36ab/src/decorator/EntityRepository.ts
https://github.com/typeorm/typeorm/blob/906d97fc8dbf1dba8f4e579a4f5bfead83af36ab/src/repository/Repository.ts
Note:
There are two solutions:
Nestjs already provides #nestjs/typeorm module and you can inject a repository for an entity easily in your service.
For example:
#Injectable()
export class UsersService {
constructor(
#InjectRepository(User)
private usersRepository: Repository<User>
) {}
...
}
You can check the documentation here - https://docs.nestjs.com/techniques/database
You can just use Active Record pattern that doesn't require a repository.
What you need to do is just to make your entities extend BaseEntity of typeorm.
For example:
#Entity()
export class User extends BaseEntity {} // <- BaseEntity
...
const user = await User.find({}) // You just use the User class for executing a query.
user.name = 'something';
await user.save();
Thanks, #yash. I could find a workaround. Defined the repo as injecatable
#Injectable()
#EntityRepository()
export class MasterDataRepo {
constructor(private manager: EntityManager) {
}
getDriveryByTerminal(terminalCode: string):Promise<Driver> {
return this.manager.findOne(Driver, { terminalCode });
}
}
and the service as
#Injectable()
export class MasterDataService {
constructor(
private masterDataRepo: MasterDataRepo,
) {}
}
Do you see any concerns?
For those using TypeORM and who had the Injection configured correctly but still running into the error:
In my case, the issue was that my #Entity was not registered in the Postgres TypeOrmModuleOptions (more precisely the entity array of the BaseConnectionOptions, cf their git repo ). Those options allow to configure Nest's TypeOrmModule
Hope this helps someone else coming to this thread
I have custom module AuthModule with AuthService, AuthController with routes and so on, that work fine, and want to share this module between several projects as a package. The questions is how to extend imported AuthService from this package and how to inject in it additional services?
More details
Into my custom AuthService, that I want to place in package, is injected class UserService, that by default gets from the database some User data and return it to client side . I need to inject into AuthService another, for example ProfileService from application, that get from database User extra data. The aim is to merge User main data and User extra data, and return this bunch to client
I don't see really the need for a Dynamic Module here.
Indeed, only is needed that the service you want to inject into other entity managed by NestJs, is exported from your AuthModule, and AuthModule imported in the Module you want other entities have injected your AuthService.
import { Module } from '#nestjs/common'
import { AuthService } from './AuthService'
#Module({
providers: [
AuthService,
// ... others
],
exports: [
AuthService
]
})
export class CommonModule {}
Then in your dependent class (let's say another Controller, but could be anything like a GraphQL Resolver, Interceptor, or whatever), you declare the dependency on AuthService.
import { AuthService } from '../auth/AuthService'
import { Dependencies } from '#nestjs/common'
#Dependencies(AuthService)
export class DependentController {
constructor (authService) {
this.authService = authService
}
}
Finally, in order to the AuthService be available to the dependent controller, it has to be imported in the same Module that controller is provided.
import { Module } from '#nestjs/common'
import { CommonModule } from '../auth/CommonModule'
import { DependentController } from './controller/DependentController'
#Module({
imports: [
CommonModule,
// ...others
],
providers: [
DependentController,
// ...others
]
})
export class ControllerModule {}
I understand that the syntax could be shorter and without using Dependencies decorator in typescript, however the core of the matter is exporting the shared Service from the Module it is provided, then importing that module into the Module other classes that require it.
This is one of the use cases Dynamic Modules have been created for.
import { Module, DynamicModule } from '#nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
#Module({
providers: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
In this example, see how providers are given (dynamically) to the result module.
Your package should follow the same pattern: expose a static method which allows building a DynamicModule, so you can resolve your other services (internal or external) as you want (building your own array of providers).
I'm using GraphQL and my resolver is decorated with #Resolver(),
so I had to not use #Dependencies (since I got a TypeError, that my functions are not functions).
I exported my service:
import { Module } from '#nestjs/common';
import { UserService } from './user.service';
import { UserResolver } from './user.resolver';
#Module({
providers: [UserResolver, UserService],
exports: [UserService], //This line is new
})
export class UserModule {}
Then, I imported it in the other module:
import { Module } from '#nestjs/common';
import { IngredientService } from './ingredient.service';
import { IngredientResolver } from './ingredient.resolver';
import { UserModule } from 'src/user/user.module'; //This line is new
#Module({
providers: [IngredientResolver, IngredientService],
imports: [UserModule], //This line is new
})
export class IngredientModule {}
Then, in my resolver, I added it in the constructor:
import { UserService } from 'src/user/user.service'; //This line is new
#Resolver(() => Ingredient)
export class IngredientResolver {
constructor(
private readonly ingredientService: IngredientService,
private readonly userService: UserService, //This line is new
) {}