Nestjs with Mongodb native driver problem with injecting the connection - mongodb

I've used Mongodb native node driver for my Nestjs project and when I run nest run command I faced this error:
Nest can't resolve dependencies of the ProjectService (?). Please make
sure that the argument DATABASE_CONNECTION at index [0] is available
in the AppModule context.
Potential solutions:
If DATABASE_CONNECTION is a provider, is it part of the current AppModule?
If DATABASE_CONNECTION is exported from a separate #Module, is that module imported within AppModule? #Module({
imports: [ /* the Module containing DATABASE_CONNECTION */ ] })
The provider for DATABASE_CONNECTION has been defined in the database module and database module has been imported in the appModule and I can't find out the problem.
src/app.module.ts
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { ProjectController } from './project/project.controller';
import { ProjectService } from './project/project.service';
import { DatabaseModule } from './database.module';
#Module({
imports: [DatabaseModule],
controllers: [AppController, ProjectController],
providers: [ProjectService],
})
export class AppModule {}
src/database.module.ts
import { Module } from '#nestjs/common';
import { MongoClient, Db } from 'mongodb';
#Module({
providers: [{
provide: 'DATABASE_CONNECTION',
useFactory: async (): Promise<Db> => {
try {
const client = await MongoClient.connect('mongodb://127.0.0.1:27017', {
useUnifiedTopology: true
});
return client.db('app-test');
} catch(e){
throw e;
}
}
}
],
exports:[
'DATABASE_CONNECTION'
]
})
export class DatabaseModule { }
src/project/project.service.ts
import { Inject, Injectable } from '#nestjs/common';
import { Db } from 'mongodb';
import { Project } from '../models/project.model';
#Injectable()
export class ProjectService {
constructor(
#Inject('DATABASE_CONNECTION')
private db: Db
) {
}
async getProjects(): Promise<Project[]> {
return this.db.collection('Projects').find().toArray();
}
}

I finally fixed the error. I removed the content of dist folder and built the project again and start it and error fixed!
I think this could be helpful https://stackoverflow.com/a/66771530/3141993 for avoiding these type of errors without removing the content of dist file manually.

Related

Trouble with module import [ NEST JS ]

I'm trying to use a jwt.strategy.ts to protect my endpoints with jwt verification. Everything was going ok until I decided to import a custom JWTService inside this jwt.strategy which contains its own JWTModule but Nest doesn't seems to recognize it. I can use the JWTService in other services but it doesn't work inside the strategy. What should I do ? What am I doing wrong ?
The NEST Message:
[Nest] 53 - 09/22/2022, 6:32:25 PM ERROR [ExceptionHandler] Nest can't resolve dependencies of the JwtStrategy (ConfigService, ?). Please make sure that the argument Object at index [1] is available in the AuthModule context.
Potential solutions:
- If Object is a provider, is it part of the current AuthModule?
- If Object is exported from a separate #Module, is that module imported within AuthModule?
#Module({
imports: [ /* the Module containing Object */ ]
})
Error: Nest can't resolve dependencies of the JwtStrategy (ConfigService, ?). Please make sure that the argument Object at index [1] is available in the AuthModule context.
Potential solutions:
- If Object is a provider, is it part of the current AuthModule?
- If Object is exported from a separate #Module, is that module imported within AuthModule?
#Module({
imports: [ /* the Module containing Object */ ]
})
The JWTModule:
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { jwtOptions } from './jwt.config';
import { JWTService } from './jwt.service';
#Module({
imports: [JwtModule.registerAsync(jwtOptions)],
providers: [JWTService],
exports: [JWTService],
})
export class JWTModule {}
The JWTService:
import { Request } from 'express';
import { DecodeOptions } from 'jsonwebtoken';
import { Injectable, UnprocessableEntityException } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { JwtService, JwtSignOptions, JwtVerifyOptions } from '#nestjs/jwt';
import { CookieHttpConfig } from '../auth';
#Injectable()
export class JWTService {
constructor(
private readonly jwtService: JwtService,
private readonly configService: ConfigService,
) {}
sign(payload: string | object | Buffer, options?: JwtSignOptions) {
return this.jwtService.sign(payload, options);
}
async signAsync(payload: string | object | Buffer, options?: JwtSignOptions) {
return this.jwtService.signAsync(payload, options);
}
verify(token: string, options?: JwtVerifyOptions) {
return this.jwtService.verify(token, options);
}
async verifyAsync(token: string, options?: JwtVerifyOptions) {
return this.jwtService.verifyAsync(token, options);
}
decode(token: string, options?: DecodeOptions) {
return this.jwtService.decode(token, options);
}
async getToken(tokenPayload: any): Promise<string> {
try {
const token: string = await this.jwtService.signAsync(tokenPayload);
return `Bearer ${token}`;
} catch (error) {
throw new UnprocessableEntityException(error.message);
}
}
async refreshToken(
cookieName: string,
request: Request,
payload: any,
): Promise<void> {
const token: string = await this.getToken(payload);
request.res.cookie(cookieName, token, CookieHttpConfig.Options());
}
}
jwt.strategy:
import { JWTService } from '#app/common';
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { PassportStrategy } from '#nestjs/passport';
import { Request } from 'express';
import { ExtractJwt, Strategy } from 'passport-jwt';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
private readonly configService: ConfigService,
private readonly jwtService: JWTService,
) {
super({
jwtFromRequest: ExtractJwt.fromExtractors([
(request: Request) => {
try {
const token = request.signedCookies['Authorization'].split(' ')[1];
return token;
} catch (error) {
return null;
}
},
]),
ignoreExpiration: false,
secretOrKey: configService.get('AUTH_JWT_SECRET'),
});
}
async validate(request: Request, payload: any): Promise<any> {
const tokenPayload = {
email: payload.email,
id: payload.id,
};
await this.jwtService.refreshToken('Authorization', request, tokenPayload);
return tokenPayload;
}
}
Extra information about my project:
I divided the project into a monorepo, so I imported the JWTModule inside the AuthModule but it still doesn't work. The jwt.strategy.ts and the JWTModule is inside a shared lib created at the same level as the apps folders containing the microservices.
The AuthModule:
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { UsersModule } from '../users/users.module';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import {
AuthLibModule,
JWTModule,
JwtStrategy,
LocalStrategy,
} from '#app/common';
import { Web3Module } from '../web3/web3.module';
import { VonageModule } from '#app/common';
#Module({
imports: [
UsersModule,
PassportModule,
JWTModule,
Web3Module,
VonageModule,
AuthLibModule,
],
controllers: [AuthController],
providers: [AuthService, LocalStrategy, JwtStrategy],
})
export class AuthModule {}

TypeError: Cannot read properties of undefined (reading 'create') + TypeORM Repository

I'm working with typeORM and Postgres in Nest.js and I'm separating my Repository from Service.
The problem is the entityRepository() decorator is not registering one of my repositories and everything points to it being fine as the same code is creating another entity's repository fine.
I've really searched and deleted the module twice thinking I might have missed something along the way, but nothing is working. When I do console.log(this) in the repository I get an empty object {}...
Below is the (module, repository, and entity) for the stock-analysis module
stock-analysis.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { StockAnalysisController } from './stock-analysis.controller';
import { StockAnalysisRepository } from './stock-analysis.repository';
import { StockAnalysisService } from './stock-analysis.service';
#Module({
imports: [TypeOrmModule.forFeature([StockAnalysisRepository])],
controllers: [StockAnalysisController],
providers: [StockAnalysisService, StockAnalysisRepository],
exports: [TypeOrmModule],
})
export class AnalysisModule {}
stock-analysis.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { StockAnalysisDto } from '../dtos/analysis/stock-analysis-dto';
import { StockAnalysis } from './stock-analysis.entity';
import { User } from '../user/user.entity';
#EntityRepository(StockAnalysis)
export class StockAnalysisRepository extends Repository<StockAnalysis> {
async analyseStock(user: User, stockAnalysisDto: StockAnalysisDto) {
const { stock } = stockAnalysisDto;
console.log({ this: this });
// console.log({ stock });
// console.log(user);
const stocksToAnalyse = this.create();
}
}
stock-analysis.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
#Entity()
export class StockAnalysis {
#PrimaryGeneratedColumn('uuid')
Id: string;
#Column('text', { array: true })
stocks: string[];
#Column()
userId: string;
}
I'm really stuck, ran out of ideas. Any form of help will be deeply appreciated
Can you try Injectable() instead of #EntityRepository(StockAnalysis)? And if that doesn't work, try to add this constructor in the repository:
constructor(private dataSource: DataSource) {
super(StockAnalysis, dataSource.createEntityManager());
}

Validation a accessToken in NESTJS

Im having some issues with validation a jwt in nestjs. Alot of documentation and tutorials show how to create token etc. I just want to validate it and protect graphql resolvers.
In my jwt.strategy.ts i have this code:
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { PassportStrategy } from '#nestjs/passport';
import { passportJwtSecret } from 'jwks-rsa';
import { ExtractJwt, Strategy } from 'passport-jwt';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService) {
super({
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'xxxxx',
}),
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
audience: 'urn:microsoft:userinfo',
issuer: 'xxxxx',
algorithms: ['RS256'],
});
}
validate(payload: unknown): unknown {
return payload;
}
}
And in my authz module i have:
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
#Module({
imports: [PassportModule.register({ defaultStrategy: 'jwt' })],
providers: [JwtStrategy],
exports: [PassportModule],
})
export class AuthzModule {}
In my resolvers i use the UseGuards decorator:
#UseGuards(AuthGuard('jwt'))
All this should work, but i get an error:
TypeError: Cannot read properties of undefined (reading 'logIn')
I dont want to do any login, just validate the token.
ANy tips on this? Have tried google, been at it for hours. Thanks!

What is the proper way to do seed mongoDB in NestJS, using mongoose and taking advantage of my already defined schmas

We are using NestJS with mongoose and want to seed mongoDB.
Wondering what is the proper way to seed the database, and use the db schemas already defined to ensure the data seeded is valid and properly maintained.
Seeding at the module level (just before the definition of the Module) feels hacky and ends in threadpool being destroyed, and therefore all following mongo operations fail
I've done using the nestjs-command library like that.
1. Install the library:
https://www.npmjs.com/package/nestjs-command
2. Then I've created a command to seed my userService like:
src/modules/user/seeds/user.seed.ts
import { Command, Positional } from 'nestjs-command';
import { Injectable } from '#nestjs/common';
import { UserService } from '../../../shared/services/user.service';
#Injectable()
export class UserSeed {
constructor(
private readonly userService: UserService,
) { }
#Command({ command: 'create:user', describe: 'create a user', autoExit: true })
async create() {
const user = await this.userService.create({
firstName: 'First name',
lastName: 'Last name',
mobile: 999999999,
email: 'test#test.com',
password: 'foo_b#r',
});
console.log(user);
}
}
3. Add that seed command into your module. I've created a SeedsModule in a shared folder to add more seeds in future
src/shared/seeds.module.ts
import { Module } from '#nestjs/common';
import { CommandModule } from 'nestjs-command';
import { UserSeed } from '../modules/user/seeds/user.seed';
import { SharedModule } from './shared.module';
#Module({
imports: [CommandModule, SharedModule],
providers: [UserSeed],
exports: [UserSeed],
})
export class SeedsModule {}
Btw I'm importing my userService into my SharedModule
4. Add the SeedsModule into your AppModule
On your AppModule usually at src/app.module.ts add the SeedsModule into imports
Final
If you followed the steps in the nestjs-command repo you should be able to run
npx nestjs-command create:user
That will bootstrap a new application and run that command and then seed to your mongo/mongoose
Hope that help others too.
actually you can do it easily with onModuleInit(), here i'm using Mongoose ORM. This all done with zero dependencies, hope it helps
import { Injectable, OnModuleInit } from '#nestjs/common';
import { UserRepository } from './repositories/user.repository';
#Injectable()
export class UserService implements OnModuleInit {
constructor(private readonly userRepository: UserRepository) {}
// onModuleInit() is executed before the app bootstraped
async onModuleInit() {
try {
const res = await this.userRepository.findAll(); // this method returns user data exist in database (if any)
// checks if any user data exist
if (res['data'] == 0) {
const newUser = {
name: 'yourname',
email: 'youremail#gmail.com',
username: 'yourusername',
};
const user = await this.userRepository.create(newUser); // this method creates new user in database
console.log(user);
}
} catch (error) {
throw error;
}
}
// your other methods
}
For my case, I needed to insert seed during the tests, the best I could find is to create a seed service, imported and used only during tests.
Here is my base class using the schema model, all is needed is to extend and pass the model.
// # base.seed.service.ts
import { Model, Document } from 'mongoose';
import { forceArray, toJson } from 'src/utils/code';
export abstract class BaseSeedService<D extends Document> {
constructor(protected entityModel: Model<D>) {}
async insert<T = any>(data: T | T[]): Promise<any[]> {
const docs = await this.entityModel.insertMany(forceArray(data));
return toJson(docs);
}
}
// # utils
const toJson = (arg: any) => JSON.parse(JSON.stringify(arg));
function forceArray<T = any>(instance: T | T[]): T[] {
if (instance instanceof Array) return instance;
return [instance];
}
// # dummy.seed.service.ts
import { Injectable } from '#nestjs/common';
import { InjectModel } from '#nestjs/mongoose';
import { Model } from 'mongoose';
import { DummyDocument } from './dummy.schema';
#Injectable()
export class DummySeedService extends BaseSeedService<DummyDocument> {
constructor(
#InjectModel(Dummy.name)
protected model: Model<DummyDocument>,
) {
super(model);
}
}
Then inside the tests
describe('Dymmy Seeds', () => {
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [DummySeedService],
imports: [
MongooseModule.forRoot(__connect_to_your_mongodb_test_db__),
MongooseModule.forFeature([
{
name: Dummy.name,
schema: DummySchema,
},
]),
],
}).compile();
const seeder = module.get<DummySeedService>(DummySeedService);
const initData = [__seed_data_here__];
const entities: Dummy[] = await seeder.insert(initData);
expect(entities.length > 0).toBeTruthy();
});
});

No Provider for AuthHttp! Angular2-Jwt provider issue

At least I thought I was providing correctly. Below are the relevant snippets of my app.module file and the service in which I use AuthHttp. I followed the configuration in the ReadMe for creating the factory method to provide for AuthHttp, but there is a persisting issue with it not being recognized in my service. I've read the literature on nested dependency injections, and I feel as though I'm doing things correctly.
app.module.ts
import { Http, RequestOptions } from '#angular/http';
import { provideAuth, AuthHttp, AuthConfig } from 'angular2-jwt/angular2-jwt';
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig(), http, options);
}
#NgModule({
declarations: [
AppComponent,
ButtonFormComponent,
...
imports: [
BrowserModule,
FormsModule,
HttpModule,
RouterModule,
AppRoutingModule
],
providers: [
{
provide: LocationStrategy,
useClass: HashLocationStrategy
},
{
provide: AuthHttp,
useFactory: authHttpServiceFactory,
deps: [Http, RequestOptions]
},
employee.service.ts
import { AuthHttp } from 'angular2-jwt/angular2-jwt';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import { ApiSettings } from './api-settings';
#Injectable()
export class EmployeeService {
api: String;
auth: String;
constructor(private http: Http, private authHttp: AuthHttp) {
this.api = ApiSettings.API;
this.auth = ApiSettings.Auth;
}
You can get rid of this issue by just using following import in your app.module.ts, here the key import for you is, AUTH_PROVIDERS.
Also, make sure you include AUTH_PROVIDERS in the providers array.
import { AuthHttp, AUTH_PROVIDERS, provideAuth, AuthConfig } from
'angular2-jwt/angular2-jwt';
#NgModule({
providers: [AUTH_PROVIDERS]
})