Winston file transport not working at Nest Js - nestjs

I recently decided to add Winston to my NestJS project and faced some problems.
Problem
When moving the instantiation of Winston to the separate file (just to keep everything nice and clean) the file transport stops working and Logger only log the stuff to the console.
However if I will follow the official documentation winston doc
and call it in main.ts during the bootstrapping than it works without any problem.
import { WinstonModule } from 'nest-winston';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: WinstonModule.createLogger({
// options (same as WinstonModule.forRoot() options)
})
});
await app.listen(3000);
}
bootstrap();
Here what I am doing and probably doing it wrong. I create helper class ->
/* eslint-disable #typescript-eslint/no-unused-vars */
import 'winston-daily-rotate-file';
import * as winston from 'winston';
import { Injectable, LogLevel, LoggerService } from '#nestjs/common';
import { join } from 'node:path';
import { utilities as nestWinstonModuleUtilities } from 'nest-winston';
#Injectable()
export class LoggerHelper implements LoggerService {
private logger: winston.Logger;
constructor() {
this.initializeLogger();
}
initializeLogger() {
this.logger = winston.createLogger({
format: winston.format.json(),
transports: [
new winston.transports.DailyRotateFile({
filename: 'application_log_%DATE%.log',
dirname: join(__dirname, './../log/debug/'),
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
level: 'error'
}),
new winston.transports.Console({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.ms(),
nestWinstonModuleUtilities.format.nestLike('App', {
prettyPrint: true
})
),
level: 'info'
})
]
});
}
log(message: any, ...optionalParams: any[]) {
this.logger.log('info',message);
}
error(message: any, ...optionalParams: any[]) {
this.logger.error('error',message);
}
warn(message: any, ...optionalParams: any[]) {
throw new Error('Method not implemented.');
}
debug?(message: any, ...optionalParams: any[]) {
throw new Error('Method not implemented.');
}
verbose?(message: any, ...optionalParams: any[]) {
throw new Error('Method not implemented.');
}
setLogLevels?(levels: LogLevel[]) {
throw new Error('Method not implemented.');
}
}
In the app module I add LoggerHelper as provider.
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './components/auth/auth.module';
import { LoggerHelper } from './setting/logger';
import { Module } from '#nestjs/common';
import { MulterModule } from '#nestjs/platform-express';
import { TypeOrmModule } from '#nestjs/typeorm';
#Module({
imports: [
TypeOrmModule.forRoot(),
UserModule,
ServiceModule,
AuthModule,
MulterModule.register({
dest: './uploads'
}),
],
controllers: [AppController],
providers: [AppService, LoggerHelper]
})
export class AppModule {}
And then use it at place I need, passing through the class constructor
import { Injectable } from '#nestjs/common';
import { LoggerHelper } from './setting/logger';
#Injectable()
export class AppService {
constructor(private logger: LoggerHelper) {}
getServerInfo(): string {
this.logger.log('test');
return 'Server information will come later';
}
}
What basically happening is that the logs goes to console but never to the file. I also tried to use default File transport instead of Daily rotate, but result is same.

Related

nestjs jwt implementation is stuck - Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?)

I'm trying to implement JWT with NestJs. In my user.module.ts, I have added following configuration:
import { Module } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { UserService } from './user.service';
import { UserResolver } from './user.resolver';
import { User } from './entities/user.entity';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AuthHelper } from './auth/auth.helper';
import { JwtStrategy } from './auth/auth.strategy';
import { PassportModule } from '#nestjs/passport';
import { JwtModule } from '#nestjs/jwt';
#Module({
imports: [
// PassportModule.register({ defaultStrategy: 'jwt', property: 'user' }),
// JwtModule.registerAsync({
// inject: [ConfigService],
// useFactory: (config: ConfigService) => ({
// secret: 'secret',
// signOptions: { expiresIn: 36000000 },
// }),
// }),
TypeOrmModule.forFeature([User]),
],
providers: [UserResolver, UserService], // AuthHelper, JwtStrategy],
})
export class UserModule {}
Whenever I uncomment these lines, I get some issues.
Here are some relevant files:
auth.strategy.ts
import { Injectable, Inject } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { PassportStrategy } from '#nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { User } from '../entities/user.entity';
import { AuthHelper } from './auth.helper';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
#Inject(AuthHelper)
private readonly helper: AuthHelper;
constructor(#Inject(ConfigService) config: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'KhubSecret',
ignoreExpiration: true,
});
}
private validate(payload: string): Promise<User | never> {
return this.helper.validateUser(payload);
}
}
auth.guard.ts
import { Injectable, ExecutionContext } from '#nestjs/common';
import { AuthGuard, IAuthGuard } from '#nestjs/passport';
import { User } from '../entities/user.entity';
#Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') implements IAuthGuard {
public handleRequest(err: unknown, user: User): any {
return user;
}
public async canActivate(context: ExecutionContext): Promise<boolean> {
await super.canActivate(context);
const { user } = context.switchToHttp().getRequest();
return user ? true : false;
}
}
auth.helper.ts:
import {
Injectable,
HttpException,
HttpStatus,
UnauthorizedException,
} from '#nestjs/common';
import { JwtService } from '#nestjs/jwt';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import * as bcrypt from 'bcryptjs';
import { User } from '../entities/user.entity';
#Injectable()
export class AuthHelper {
#InjectRepository(User)
private readonly repository: Repository<User>;
private readonly jwt: JwtService;
constructor(jwt: JwtService) {
this.jwt = jwt;
}
public async decode(token: string): Promise<unknown> {
return this.jwt.decode(token, null);
}
public async validateUser(decoded: any): Promise<User> {
return this.repository.findOne(decoded.id);
}
public generateToken(user: User): string {
return this.jwt.sign({
id: user.userId,
username: user.username,
});
}
public isPasswordValid(password: string, userPassword: string): boolean {
return bcrypt.compareSync(password, userPassword);
}
public encodePassword(password: string): string {
const salt: string = bcrypt.genSaltSync(10);
return bcrypt.hashSync(password, salt);
}
private async validate(token: string): Promise<boolean | never> {
const decoded: unknown = this.jwt.verify(token);
if (!decoded) {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
const user: User = await this.validateUser(decoded);
if (!user) {
throw new UnauthorizedException();
}
return true;
}
}
I get some error like this:
[Nest] 18360 - 05/10/2022, 18:14:42 ERROR [ExceptionHandler] Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument ConfigService at index [0] is available in the JwtModule context.
Potential solutions:
- If ConfigService is a provider, is it part of the current JwtModule?
- If ConfigService is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing ConfigService */ ]
})
Error: Nest can't resolve dependencies of the JWT_MODULE_OPTIONS (?). Please make sure that the argument ConfigService at index [0] is available in the JwtModule context.
Potential solutions:
- If ConfigService is a provider, is it part of the current JwtModule?
- If ConfigService is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing ConfigService */ ]
})
I have already tested and implemented these solutions:
NestJS can't resolve dependencies of the JWT_MODULE_OPTIONS
Here is the solution. I hope it would help.
In your auth strategy add this:
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'KhubSecret',
ignoreExpiration: true,
});
}
instead of:
constructor(#Inject(ConfigService) config: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'KhubSecret',
ignoreExpiration: true,
});
}
In Short, Remove
#Inject(ConfigService) config: ConfigService
from your constructor
From the immediate error you've provided, I'll assume that your ConfigModule is not global. This means that you'll need to import the ConfigModule in the JwtModule.registerAsync() call (in the imports array). Another option would be to make your ConfigModule global (#nestjs/config has an option for this) so that you already have access to ConfigService.

Mock Injected Twilio Service in Unit Testing Nest.js

I have a problem with overriding provider/setup module testing in nest.js application for testing.
Module file: smsModule.ts:
import { TwilioService } from './twilio/twilio.service';
import { DynamicModule, Module } from '#nestjs/common';
import { TwilioConfig, SMS_TWILIO_CONFIG } from './twilio.config';
import { TwilioClientCustom } from './twilio/twilio-client-custom';
#Module({
imports: [],
providers: [TwilioService],
})
export class SmsModule {
static register(options: TwilioConfig): DynamicModule {
return {
module: SmsModule,
imports: [HttpModule],
providers: [
{
provide: SMS_TWILIO_CONFIG,
useValue: options,
},
TwilioService,
TwilioClientCustom,
],
exports: [TwilioService],
};
}
}
Twilio client, config files:
//client
import { TwilioConfig, SMS_TWILIO_CONFIG } from '../twilio.config';
import { Twilio } from 'twilio';
import { Inject, Injectable } from '#nestjs/common';
#Injectable()
export class TwilioClientCustom extends Twilio {
constructor(#Inject(SMS_TWILIO_CONFIG) twilioConfig: TwilioConfig) {
super(twilioConfig.accountSid, twilioConfig.authToken);
}
}
//config
import { IsString, IsNotEmpty, NotContains, IsOptional, IsArray } from 'class-validator';
const INFO = 'Must be ....';
export class TwilioConfig {
#IsString()
#IsNotEmpty()
#NotContains('OVERRIDE_WITH_', { message: INFO })
accountSid: string;
#IsString()
#IsNotEmpty()
authToken: string;
#IsArray()
#IsOptional()
#IsNotEmpty('OVERRIDE_WITH_', { message: INFO })
serviceSid: string;
}
export const SMS_TWILIO_CONFIG = 'smsTwilioConfig';
Twilio service file: twilio.service.tst:
import { HttpService } from '#nestjs/axios';
import { TwilioConfig, SMS_TWILIO_CONFIG } from '../twilio.config';
import { SendSmsTwilioService } from './../sendsms.service';
import { Inject, Injectable } from '#nestjs/common';
import { TwilioClientCustom } from './twilio-client-custom';
#Injectable()
export class TwilioService implements SendSmsTwilioService {
constructor(
#Inject(SMS_TWILIO_CONFIG) private readonly config: TwilioConfig,
private readonly client: TwilioClientCustom,
private readonly httpService: HttpService
) {}
async sendSMS(to: string, from: string, body: string): Promise<string> {
......
return this.client.messages
.create({
to, //Recipinet's number
from, //Twilio number
body, //Messages to Recipient
})
.then((message) => message.sid)
.catch(() => {
throw new Error('TWILIO accountSid or authToken not valid');
});
}
I would like to test my service:
test file:
import { Test, TestingModule } from '#nestjs/testing';
//import { TWILIO_CONFIG_SPEC } from './test.config';
import { TwilioClientCustom } from '../src/twilio/twilio-client-custom';
import { HttpService } from '#nestjs/axios';
import { TwilioConfig } from './../src/twilio.config';
import { TwilioService } from './../src/twilio/twilio.service';
import nock from 'nock';
describe('TwilioService', () => {
let service: TwilioService;
let client: TwilioClientCustom;
let httpService: HttpService;
afterEach(() => {
nock.cleanAll();
});
//const smsServiceMock = {};
beforeEach(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
providers: [
TwilioService,
{
provide: HttpService,
useValue: {
method1: jest.fn(),
method2: jest.fn(),
method3: jest.fn(),
},
},
TwilioService,
],
imports: [
NestConfigModule.forRoot({
config: TwilioConfig,
} as Record<string, unknown>),
],
}).compile();
//getting service module from main module
httpService = moduleRef.get<HttpService>(HttpService);
client = moduleRef.get<TwilioClientCustom>(TwilioClientCustom);
service = moduleRef.get<TwilioService>(TwilioService);
});
//check service is avaible
it('Should be defined', () => {
expect(client).toBeDefined();
expect(service).toBeDefined();
expect(httpService).toBeDefined();
});
And after running test I get following errors:
Nest can't resolve dependencies of the TwilioService (?, TwilioClientCustom, HttpService). Please make sure that the argument smsTwilioConfig at index [0] is available in the RootTestModule context.
Potential solutions:
- If smsTwilioConfig is a provider, is it part of the current RootTestModule?
- If smsTwilioConfig is exported from a separate #Module, is that module imported within RootTestModule?
#Module({
imports: [ /* the Module containing smsTwilioConfig */ ]
})
How can I solve this problem ?
smsTwilioConfig is registered with Nest's IOC via SmsModule.register(opts).
However, it seems you're attempting to test TwilioService directly with createTestingModule. Which is fine, but it does mean you need include the config with a provider or import in your test.
My guess is that you thought NestConfigModule... would do that, but that's not setting the config at the right level.
I would think the following is the right direction
const moduleRef: TestingModule = await Test.createTestingModule({
providers: [
TwilioService,
{
provide: HttpService,
useValue: {
method1: jest.fn(),
method2: jest.fn(),
method3: jest.fn(),
},
},
{
// added this
provide: SMS_TWILIO_CONFIG,
useValue: testConfig
},
],
imports: [
// removed NestConfigModule
],
}).compile();

nestjs isn't injecting the typeorm connection in a custom validator

I am in the process of working out a custom validator to be used to verify if a value exists in the database
I managed to get the code to work by using getConnection() from the typeorm package. But I would ideally want to inject the typeorm connection object constructor(private connection: Connection) {} this gives me more flexibility with the testing.
import { BadRequestException, Injectable } from '#nestjs/common';
import {
ValidationArguments,
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
import { Connection, getConnection } from 'typeorm';
#ValidatorConstraint({ name: 'ExistsRule', async: true })
#Injectable()
export class ExistsRule implements ValidatorConstraintInterface {
constructor(private connection: Connection) {}
async validate(value: number | string, args: ValidationArguments) {
const { constraints } = args;
if (constraints.length === 0) {
throw new BadRequestException(`Failed validating ${value} exists.`);
}
const str = constraints[0].split(':');
const tableName = str[0];
const columnName = str[1];
const result = await getConnection().query(
`select count(*) from ${tableName} where ${columnName}=$1`,
[value],
);
// The record already exists. Failing the validation.
if (result[0].count > 0) {
return false;
}
return true;
}
defaultMessage(args: ValidationArguments) {
const { property, value } = args;
return `${property} ${value} is already taken.`;
}
}
DTO that is using this validator. (For completeness)
import {
IsEmail,
IsNotEmpty,
IsPhoneNumber,
IsString,
Validate,
} from 'class-validator';
import { ExistsRule } from 'src/customer/exists.validator';
export class CreateCustomerDto {
#IsString()
firstName: string;
#IsString()
lastName: string;
#IsEmail()
#Validate(ExistsRule, ['customer:email'])
email: string;
#IsPhoneNumber()
mobileNumber: string;
#IsNotEmpty()
password: string;
}
#Module({
imports: [
TypeOrmModule.forFeature([Customer]),
JwtModule.register({
secret: 'secret-to-be-put-in-the-env',
signOptions: { expiresIn: '300s' },
}),
CommonModule,
],
controllers: [BookingsController, AuthController],
providers: [CustomerService, AuthService, LocalStrategy, JwtStrategy],
})
export class CustomerModule {}
import { Module } from '#nestjs/common';
import { UniqueRule } from './unique.validator';
#Module({
providers: [UniqueRule],
})
export class CommonModule {}
Thanks to #JayMcDoniel's comments, and guidence. The solution was to edit main.ts and add the useContainer from class-validator module to instruct it to use the nestjs container.
import { ValidationPipe } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import { useContainer } from 'class-validator';
import { AppModule } from './app.module';
import { CommonModule } from './common/common.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
);
useContainer(app.select(CommonModule), { fallbackOnErrors: true });
await app.listen(3000);
}
bootstrap();

Nestjs graphql upload error: POST body missing. Did you forget use body-parser middleware?

I'm using NestJS 7 with graphql on node v14x
This is my graphql module configuration
import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '#nestjs/common';
import { graphqlUploadExpress } from "graphql-upload"
import { GraphQLModule } from '#nestjs/graphql';
import { ConfigService } from '#nestjs/config';
import { ApolloServerDataLoaderPlugin } from '#webundsoehne/nestjs-graphql-typeorm-dataloader';
import { GraphqlConfig } from './#core/config/config.interface';
import { getConnection } from 'typeorm';
#Module({
imports: [
GraphQLModule.forRootAsync({
useFactory: async (configService: ConfigService) => {
const graphqlConfig = configService.get<GraphqlConfig>('graphql');
return {
buildSchemaOptions: {
numberScalarMode: 'integer',
plugins: [new ApolloServerDataLoaderPlugin({ typeormGetConnection: getConnection })]
},
sortSchema: graphqlConfig.sortSchema,
autoSchemaFile:
graphqlConfig.schemaDestination || './src/schema.graphql',
debug: graphqlConfig.debug,
path: graphqlConfig.endPoint,
uploads: false,
playground: graphqlConfig.playgroundEnabled,
context: ({ req, connection }) => {
if (connection) {
return { req: { headers: connection.context } }
}
return { req }
},
installSubscriptionHandlers: true,
dateScalarMode: "isoDate",
subscriptions: {
keepAlive: 5000
}
};
},
inject: [ConfigService],
}),
],
})
export class GQLModule implements NestModule {
constructor(private readonly configService: ConfigService) { }
configure(consumer: MiddlewareConsumer) {
const graphqlConfig = this.configService.get<GraphqlConfig>('graphql');
consumer.apply(graphqlUploadExpress()).forRoutes(graphqlConfig.endPoint)
}
}
After getting stuck on file upload not working on node v14.x, I find this issue comment. And I'm importing everything from graphql-upload on my resolver, But still getting error message like POST body missing. Did you forget use body-parser middleware?
Can anybody help me on this?
I have nearly identical configuration, and it works correctly for me. Since I use both REST and GraphQL, I have limited the route to 'graphql'
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { ServeStaticModule } from '#nestjs/serve-static';
import { MongooseModule } from '#nestjs/mongoose';
import { GraphQLModule } from '#nestjs/graphql';
import { AuthorModule } from '../author/author.module';
import { ApiService } from './api.service';
import { join } from 'path';
const {
graphqlUploadExpress,
} = require('graphql-upload');
const isLocalEnvironment = () => process.env.ENV === 'local';
console.log('isLocal', isLocalEnvironment(), process.env.ENV);
const modules = [
AuthorModule,
GraphQLModule.forRoot({
playground: isLocalEnvironment(),
fieldResolverEnhancers: ['guards'],
debug: isLocalEnvironment(),
autoSchemaFile: isLocalEnvironment() ? 'schema.gql' : true,
introspection: isLocalEnvironment(),
useGlobalPrefix: true,
context: ({ req }) => ({ req }),
}),
MongooseModule.forRoot(process.env.COSMOSDB_CONNECTION_STRING, {
useNewUrlParser: true,
useUnifiedTopology: true,
retryWrites: false,
autoIndex: true,
}),
];
#Module({
imports: modules,
providers: [ApiService],
})
export class APIModule implements NestModule{
configure(consumer: MiddlewareConsumer) {
consumer.apply(graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 })).forRoutes('graphql');
}
}
In my main.ts file, I bootstrap the application.
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
import { NestFactory } from '#nestjs/core';
import { APIModule } from './api/api.module';
import { INestApplication } from '#nestjs/common';
import { json, urlencoded } from 'body-parser';
import 'isomorphic-fetch';
const prefix = "api/";
async function bootstrap() {
const port = process.env.PORT;
const app: INestApplication = await NestFactory.create(APIModule);
app.enableCors();
app.use(json({ limit: '50mb' }));
app.use(urlencoded({ limit: '50mb', extended: true }));
// Because I use the global prefix of api/, I need to hit my service at /api/graphql
app.setGlobalPrefix(prefix);
console.log('Starting on port ' + port);
await app.listen(port);
return app;
}
bootstrap();
Since your configuration looks good to me, I'm guessing something went wrong in your bootstrap function, or that you aren't hitting the /graphql route.
I am using the latest version of NestJS which no longer includes a graphql upload implementation, so unlike you, I do not need to turn uploads off.

Nest JS - Return undefined when trying to get user context in RolesGuard

I am trying to add role guard in Nest JS API. I used Passport, Jwt authentication for this.
In my RolesGuard class I made the request and get the user from it to check the user role valid or not. I attached the code below.
roles.guard.ts
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user: User = request.user;
return this.userService.findOne(user.id).pipe(
map((user: User) => {
const hasRole = () => roles.indexOf(user.role) > -1;
let hasPermission: boolean = false;
if (hasRole()) {
hasPermission = true;
}
return user && hasPermission;
}),
);
}
Problem here is context.switchToHttp().getRequest() returns object, which is undefined. So I could not get user details from it.
After I had some research about this error I found that order of the decorators in controller can be the issue. Then I changed the order, but still problem appears as same. Bellow I added that code also.
user.controller.ts
#UseGuards(JwtAuthGuard, RolesGuard)
#hasRoles(UserRole.USER)
#Get()
findAll(): Observable<User[]> {
return this.userService.findAll();
}
-Thank you-
if you are using graphql you can make the changes to fit the code below
import { Injectable, CanActivate, ExecutionContext } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
import { GqlExecutionContext } from '#nestjs/graphql';
import { Role } from 'src/enums/role.enum';
import { ROLES_KEY } from '../auth';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const ctx = GqlExecutionContext.create(context);
const user = ctx.getContext().req.user;
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
if you are not using graphql, make the changes to fit the code below
import { Injectable, CanActivate, ExecutionContext } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
then in you controller you can do
#UseGuards(JwtAuthGuard, RolesGuard)
#hasRoles(UserRole.USER)
#Get()
findAll(): Observable<User[]> {
return this.userService.findAll();
}
finally, for all this to work add the global guard to your app.module.ts
like so
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import {MongooseModule} from '#nestjs/mongoose';
import { AppService } from './app.service';
import { ConfigModule } from '#nestjs/config';
import configuration from 'src/config/configuration';
import { RolesGuard } from 'src/auth/auth';
import { UsersModule } from '../users/users.module';
import { AdminsModule } from 'src/admin/admins.module';
import { config } from 'dotenv';
import * as Joi from 'joi';
config();
#Module({
imports: [
// other modules
UsersModule,
// configuration module
ConfigModule.forRoot({
isGlobal: true,
cache: true,
load: [configuration],
expandVariables: true,
// validate stuff with Joi
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production', 'test', 'provision')
.default('development'),
PORT: Joi.number().default(5000),
}),
validationOptions: {
// allow unknown keys (change to false to fail on unknown keys)
allowUnknown: true,
abortEarly: true,
},
}),
// connect to mongodb database
MongooseModule.forRoot(process.env.DB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
}),
],
controllers: [AppController],
providers: [
AppService,
{
provide: 'APP_GUARD',
useClass: RolesGuard,
}
],
})
export class AppModule {}

Resources