Nest can't resolve dependencies of the RestController - javascript

I'm working in a new Nest.js project and whenever I try to start the server:
[ExceptionHandler] Nest can't resolve dependencies of the RestController (?). Please make sure that the argument dependency at index [0] is available in the RestModule context.
I've checked the documentation and looked everywhere and i cannot spot the problem. The RestController class injects UsersService, which is exported by UsersModule and imported in RestModule. Everything looks fine but didn't work.
This is my code:
app.module.ts:
import { Module } from '#nestjs/common'
import { RestModule } from './rest/rest.module'
#Module({
imports: [
RestModule
]
})
export class AppModule { }
rest.module.ts:
import { Module } from '#nestjs/common'
import { RestController } from './rest.controller'
import { UsersModule } from '../users/users.module'
#Module({
imports: [
UsersModule
],
controllers: [
RestController
]
})
export class RestModule { }
rest.controller.ts:
import { Controller, Inject, Get } from '#nestjs/common'
import { UsersService } from '../users/users.service'
import { User } from '../users/user.interface'
#Controller()
export class RestController {
constructor (
#Inject()
private readonly usersService: UsersService
) { }
#Get()
async getAll (): Promise<User[]> {
return this.usersService.findAll()
}
}
users.module.ts:
import { Module } from '#nestjs/common'
import { UsersService } from './users.service'
#Module({
providers: [
UsersService
],
exports: [
UsersService
]
})
export class UsersModule { }
users.service.ts:
import { Injectable } from '#nestjs/common'
import { User } from './user.interface'
#Injectable()
export class UsersService {
async findAll (): Promise<User[]> {
return new Promise((resolve, reject) => resolve([]))
}
}
Thank you in advance!

In your RestController class you have to remove the #Inject() from your constructor:
constructor (
private readonly usersService: UsersService
) { }
#Inject() can be used for non-class-based provider tokens.

Related

NestJs: How can I inject a Provider that has a constructor with a Mongoose Model?

Hi I have the following code in NestJS.I am using moduleRef and have declared a custom provider named 'blogService'.However I am getting an error that says:
'Nest can't resolve dependencies of the blogService (?). Please make
sure that the argument BlogModel at index [0] is available in the
AppModule context.'
.What exactly am I doing wrong while declaring the custom provider which is leading to this error as it seems that I am injecting the Mongoose Model as well?
app.module.ts
import { BlogService } from './blog/service/blog.service';
import { Blog } from './blog/schema/blog.schema';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '#nestjs/config';
import { MongooseModule, getModelToken } from '#nestjs/mongoose';
#Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, load: [configuration], }),
MongooseModule.forRoot(process.env.DATABASE_URL)
],
controllers: [AppController],
providers: [AppService, {
provide: 'blogService',
useFactory: () => BlogService,
inject: [getModelToken(Blog.name)]
}],
})
app.controller.ts
import { Controller, Get } from '#nestjs/common';
import { ModuleRef } from '#nestjs/core';
import { BlogService } from './blog/service/blog.service';
#Controller()
export class AppController {
constructor(private readonly modelRef: ModuleRef) { }
#Get('blogs')
async getAllBlogs(): Promise<any> {
const response = await this.modelRef.get('blogService', { strict: false }).getAllBlogs();
return response;
}
}
blog.service.ts
import { Injectable, HttpException, HttpStatus, Logger } from '#nestjs/common';
import { Blog } from '../schema/blog.schema';
import { InjectModel } from '#nestjs/mongoose';
import { Model, Types } from 'mongoose';
#Injectable()
export class BlogService {
private readonly logger = new Logger(BlogService.name);
constructor(#InjectModel(Blog.name) private blogModel: Model<Blog>) { }
async getAllBlogs() {
try {
const blogs = await this.blogModel.find().exec();
return blogs;
} catch (error) {
this.logger.error(error.message);
}
}
}
Not really sure why you're making a custom provider for this, other than possibly academic purposes. Either way, for anything you want to #InjectModel() or use getModelToken() for, you needx to have a MongooseModule.forFeature() call to register the custom provider the #nestjs/mongoose package will create for you. Once you have this you can use #InjectModel() or a custom provider like
{
provide: 'blogService',
inject: [getModelToken(Blog.name)],
useFactory: (model: Model<Blog>) => new BlogService(model)
}

NestJS - Error: Unknown authentication strategy "local"

These are the partial NestJS code snippets I have. I am trying to implement the passport local strategy for getting the username and password. I am getting -Error: Unknown authentication strategy "local", in the controller file when using the auth guard.
AuthModule.ts
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { PassportModule } from '#nestjs/passport';
import { UserModule } from 'src/user/user.module';
import { JwtAuthController } from './jwt-auth.controller';
import { JwtAuthService } from './jwt-auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';
#Module({
imports: [
UserModule,
PassportModule,
JwtModule.register({
secret: process.env.SECRETKEY,
signOptions: { expiresIn: '3600s' }
})
],
controllers: [JwtAuthController],
providers: [JwtAuthService, LocalStrategy, JwtStrategy],
exports: [JwtAuthService],
})
export class JwtAuthModule {}
local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
import { JwtAuthService } from './jwt-auth.service';
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
constructor(private authService: JwtAuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser({username, password});
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
app.controller.ts
import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { JwtAuthService } from './jwt-auth/jwt-auth.service';
#Controller()
export class AppController {
constructor(private readonly authService: JwtAuthService) {}
#UseGuards(AuthGuard('local'))
#Post('/auth/login')
async login(#Req() req) {
return this.authService.login(req.user)
}
}
I am getting the following error on calling /auth/login API
[Nest] 26753 - 10/31/2021, 22:08:18 ERROR [ExceptionsHandler] Unknown authentication strategy "local"
Error: Unknown authentication strategy "local"
Am I missing anything? Thanks in advance.
just add the PassportModule and LocalStrategy in app.module .it will be fixed
#Module({
imports: [PassportModule],
providers: [AuthService,LocalStrategy],
})
export class AppModule {}
Fix Bug https://github.com/nestjs/nest/issues/4646
File AUTH.ts
enter code here
import { Module } from '#nestjs/common';
import { JwtModule } from '#nestjs/jwt';
import { PassportModule } from '#nestjs/passport';
import { UserModule } from 'src/user/user.module';
import { JwtAuthController } from './jwt-auth.controller';
import { JwtAuthService } from './jwt-auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';
#Module({
imports: [
UserModule,
PassportModule.register({defaultStrategy:'local'}),
JwtModule.register({
secret: process.env.SECRETKEY,
signOptions: { expiresIn: '3600s' }
})
],
controllers: [JwtAuthController],
providers: [JwtAuthService, LocalStrategy, JwtStrategy],
exports: [JwtAuthService],
})
export class JwtAuthModule {}
Such an old question with no answers...
In my case I was having sort of an cyclic dependency issue. Or at least it was what it looked like. Cyclic deps can be either on nest side or even on node.js require side (on the second case we end up with empty imports).
Case 1:
#Injectable()
export class MyLocalStrategy extends PassportStrategy(PassportLocalStrategy) {
hello = 'hello'
constructor(private authService: AuthService) {
console.log('load local strategy')
}
}
#Module({
imports: [
CommonModule,
PassportModule,
JwtModule.registerAsync({
async useFactory(config: ConfigService) {
const jwtSecret = config.get('APP_KEY')
const expiresIn = config.get('AUTH_TOKEN_EXPIRED')
return {
secret: jwtSecret,
signOptions: {
expiresIn,
},
}
},
inject: [ConfigService],
}),
],
providers: [
RoleService,
JwtStrategy,
JwtService,
AuthService,
],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
const moduleRef = this.moduleRef
console.log('init auth module')
const local = moduleRef.get(MyLocalStrategy)
const auth = moduleRef.get(AuthService)
console.log('my modules', { local, auth }, local?.hello)
}
}
In this case the "load local strategy" never got logged. Yet "my modules" logged an empty localStrategy instance, without my "hello" property. Weird!
I hacked a fix by moving the class instantiation to a factory provider, and by requiring the dependencies with ModuleRef. The following excerpt worked fine.
#Module({
imports: [
CommonModule,
PassportModule,
JwtModule.registerAsync({
async useFactory(config: ConfigService) {
const jwtSecret = config.get('APP_KEY')
const expiresIn = config.get('AUTH_TOKEN_EXPIRED')
return {
secret: jwtSecret,
signOptions: {
expiresIn,
},
}
},
inject: [ConfigService],
}),
],
providers: [
RoleService,
JwtStrategy,
JwtService,
AuthService,
{
provide: MyLocalStrategy,
useFactory: (moduleRef: ModuleRef) => {
const auth = moduleRef.get(AuthService)
console.log('local strat factory', { auth })
return new MyLocalStrategy(auth)
},
inject: [ModuleRef],
},
],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
const moduleRef = this.moduleRef
console.log('init auth module')
const local = moduleRef.get(MyLocalStrategy)
const auth = moduleRef.get(AuthService)
console.log('local', { local, auth }, local?.hello)
}
}
I also tried factory + injecting AuthService directly (through providers array, instead of using ModuleRef). I got a null AuthService.
Probably some dependency cycle on the node.js module imports, tough neither eslint or nest wouldn't say anything.
Check to see if your auth module is being imported in your entry file. app.module.ts.
My auth-module.ts
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
#Module({
imports:[UsersModule,PassportModule],
providers: [AuthService,LocalStrategy]
})
export class AuthModule {}
My app module
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
#Module({
imports:[UsersModule,PassportModule],
providers: [AuthService,LocalStrategy]
})
export class AuthModule {}
NestJs encourages scalability and therefore organizes your code in modules.
Instead of calling JwtAuthService method in the AppController, do it in the JwtAuthController. Your code should look like this:
import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { JwtAuthService } from './jwt-auth.service';
#Controller('auth')
export class JwtAuthController {
constructor(private readonly authService: JwtAuthService) {}
#Post('/login')
#UseGuards(AuthGuard('local'))
async login(#Req() req) {
return req.user
}
}
Nest will then instantiate all providers in the JwtAuthModule such that it will be available in it's controller (JwtController).
You Can always optimize your code by moving AuthGuard to it own file local.guard.ts given you the possibility to do any additional business logic.
import { ExecutionContext } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { Request } from 'express';
export class LocalGuard extends AuthGuard('local') {}
You need to import the module that implements the authentications.
It can be inside app.module.ts or inside another module that is connected to it.
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
#Module({
imports: [UsersModule, AuthModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
There is a workaround that may clarify things better
https://docs.nestjs.com/techniques/authentication#request-scoped-strategies
I have the same issue with you. My solution is importing LocalStrategy class to module file, in which I use AuthGuard for API endpoint.
For example: in file user.controller.ts I have AuthGuard('local') in the endpoint /login with method POST
//user.controller.ts
#UseGuards(AuthGuard('local'))
#Post('login')
async login (#Request() req: any) {
return req.user;
}
In my case, I just add LocalStrategy class (I also have this class in local.strategy.ts like you) in module file:
//user.module.ts
#Module({
imports: [
...
LocalStrategy,
],
controllers: [UserController],
...
}
Conclusion, NestJs is quite complicated in importing modules, don't forget to import what you want into other modules. Good luck!

NestJS Dependency Injection Error: provider/module is not part of currently processed module

I've just started with NestJS and I'm wondering what the best way to solve this error is
Nest cannot export a provider/module that is not a part of the
currently processed module (UsersModule). Please verify whether the
exported UsersService is available in this particular context.
I am following along with the documentation here and I seem to have hit a brick wall. My app won't compile so I can't test any further. I'll add some of the files as examples.
auth.module.ts
import { Module } from '#nestjs/common';
import { UsersModule } from 'src/users/users.module';
import { AuthController } from './controllers/auth/auth.controller';
import { AuthService } from './services/auth/auth.service';
#Module({
imports: [UsersModule],
controllers: [AuthController],
providers: [AuthService],
exports: [AuthService],
})
export class AuthModule {}
users.module.ts
import { Module } from '#nestjs/common';
import { MongooseModule } from '#nestjs/mongoose';
import { UsersController } from './controllers/users/users.controller';
import { User, UserSchema } from './schemas/user.schema';
import { UsersService } from './services/users/users.service';
#Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [
{
provide: 'USERS_SERVICE',
useClass: UsersService,
},
],
exports: [UsersService],
})
export class UsersModule {}
users.service.ts
import { Injectable } from '#nestjs/common';
import { InjectModel } from '#nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateUserDto } from 'src/users/dto/user.dto';
import { User, UserDocument } from 'src/users/schemas/user.schema';
import { IUserService } from './user';
#Injectable()
export class UsersService implements IUserService {
constructor(#InjectModel(User.name) private userModel: Model<UserDocument>) {}
// async code for database modification
}
}
Any help would be greatly appreciated! Many thanks!
The token of UsersService provider is the string 'UsersService' (or UsersService.name) not 'USERS_SERVICE'
So just use the short-hand syntax providers: [UsersService] or the right token in provide:.

Nest.js cant resolve dependencies, can't find my mistake

I'm doing a Nest.js program but I can't find my dependencies problem. I have searched quite a lot and I have found a lot of answers regarding this problem, but I can't figure out why my code isn´t working. So I have a product module which has his DTO´s, Entity, Controller, Service and module, besides it has an interface for its service.
ProductController
import { Controller, Get } from '#nestjs/common';
import { ProductServiceInterface } from './interface/product.service.interface'
#Controller('products')
export class ProductController {
constructor(private readonly productService: ProductServiceInterface) {}
#Get()
getHello(): string {
return this.productService.test();
}
}
ProductServiceInterface
import { Injectable } from '#nestjs/common';
import {
CreateProductInput,
CreateProductOutput,
} from '../dto/create-product.dto';
import { FindProductOutput } from '../dto/find-product.dto';
export interface ProductServiceInterface {
create(input: CreateProductInput): Promise<CreateProductOutput>;
findProduct(productId: string): Promise<FindProductOutput>;
test();
}
ProductService
import { Injectable } from '#nestjs/common';
import { ProductServiceInterface } from './interface/product.service.interface';
import {
CreateProductInput,
CreateProductOutput,
} from './dto/create-product.dto';
import { Product } from './entity/product.entity';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { FindProductOutput } from './dto/find-product.dto';
//import WooCommerce from '../../config/woocomerce.config';
#Injectable()
export class ProductService implements ProductServiceInterface {
constructor(
#InjectRepository(Product)
private productRepository: Repository<Product>,
) {}
public async create(
productDto: CreateProductInput,
): Promise<CreateProductOutput> {
const product = new Product();
product.name = productDto.name;
product.price = productDto.price;
product.imgUrl = productDto.imgUrl;
const savedProduct = await this.productRepository.save(product);
const productOutput = new CreateProductOutput();
productOutput.id = savedProduct.id;
return productOutput;
}
public async findProduct(idProduct: string): Promise<FindProductOutput> {
const fetchedProduct = await this.productRepository.findOne(idProduct);
const productOutput = new FindProductOutput();
productOutput.id = fetchedProduct.id;
productOutput.imgUrl = fetchedProduct.imgUrl;
productOutput.name = fetchedProduct.name;
productOutput.price = fetchedProduct.price;
return productOutput;
}
public test() {
return 'test'
// WooCommerce.get('products', {
// pero_page: 20,
// }).then((resp) => {
// return resp;
// });
}
}
ProductModule
import { ProductController } from './product.controller';
import { ProductService } from './product.service';
import { Product } from './entity/product.entity';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Module } from '#nestjs/common';
#Module({
imports: [TypeOrmModule.forFeature([Product])],
controllers: [ProductController],
providers: [ProductService],
})
export class ProductModule {}
AppModule
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '#nestjs/config';
import configuration from 'src/config/configuration';
import { TypeOrmModule } from '#nestjs/typeorm';
import { TypeOrmConfigService } from 'src/config/typeorm.config.service';
import { ProductModule } from './modules/product/product.module';
#Module({
imports: [
ConfigModule.forRoot({
load: [configuration],
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
useClass: TypeOrmConfigService,
}),
ProductModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
I hope this code is enough for knowing where my mistake is, I don't like letting others just resolve this for me but I've been watching my code for hours and can't know how to resolve this dependencies problem.
Interfaces disappear at runtime and becomes {} or Object. Nest uses the parameter type metadata to determine what is supposed to be injected (usually via ClassType.name). You have two options to solve this
Use an abstract class instead of an interface. This makes the class still visible at runtime so ClassType.name still works.
Use #Inject('CustomToken') as the way to set the metadata for what Nest needs to inject. You then need to make sure register the custom provider using something like
{
provide: 'CustomToken',
useClass: ClassToBeUsed
}
Either of these methods should fix your issue.

Nest can't resolve dependencies of custom service

I am basically follow this tutorial with very minor modifications:link
I am using nest 6.14.2 on node 12.10.0.
When running my app I get:
> recon-backend#0.0.1 start C:\Users\e5553079\Desktop\Node_Projects\recon-backend
> nest start
[Nest] 8324 - 02/10/2020, 9:28:21 AM [NestFactory] Starting Nest application...
[Nest] 8324 - 02/10/2020, 9:28:21 AM [InstanceLoader] MongooseModule dependencies initialized +53ms
[Nest] 8324 - 02/10/2020, 9:28:21 AM [ExceptionHandler] Nest can't resolve dependencies of the ReconQueryService (?). Please make sure that the argument ReconQueryModel at index [0] is available in the AppModule context.
Potential solutions:
- If ReconQueryModel is a provider, is it part of the current AppModule?
- If ReconQueryModel is exported from a separate #Module, is that module imported within AppModule?
#Module({
imports: [ /* the Module containing ReconQueryModel */ ]
})
+2ms
Error: Nest can't resolve dependencies of the ReconQueryService (?). Please make sure that the argument ReconQueryModel at index [0] is available in the AppModule context.
My files look like this:
1. app.module.ts
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQueryModule } from './reconQuery/reconQuery.module';
import { ReconQueryService } from './reconQuery/reconQuery.service';
import { ReconQueryController } from './reconQuery/reconQuery.controller';
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/backend-app', { useNewUrlParser: true }),
ReconQueryModule
],
controllers: [AppController, ReconQueryController],
providers: [AppService, ReconQueryService],
})
export class AppModule {}
2. reconQuery.service.ts
import { Injectable } from '#nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '#nestjs/mongoose';
import { ReconQuery } from './interfaces/reconQuery.interface';
import { CreateReconQueryDTO } from './dto/create-reconQuery.dto';
#Injectable()
export class ReconQueryService {
constructor(#InjectModel('ReconQuery') private readonly reconQueryModel: Model<ReconQuery>) { }
// Fetch all queries
async getAllQueries(): Promise<ReconQuery[]> {
const queries = await this.reconQueryModel.find().exec();
return queries;
}
...
3. reconQuery.interface.ts
import { Document } from 'mongoose';
export interface ReconQuery extends Document {
readonly id: number;
readonly name: string;
readonly sql: string;
}
4. reconQuery.module.ts
import { Module } from '#nestjs/common';
import { ReconQueryController } from './reconQuery.controller';
import { ReconQueryService } from './reconQuery.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQuerySchema } from './schemas/reconQuery.schema';
#Module({
imports: [
MongooseModule.forFeature([{ name: 'ReconQuery', schema: ReconQuerySchema }])
],
controllers: [ReconQueryController],
providers: [ReconQueryService]
})
export class ReconQueryModule {}
I wonder why it cries about ReconQueryModel as I do not have such an entity, just a ReconQuery interface.
You have extra ReconQueryService provided in AppModule.
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQueryModule } from './reconQuery/reconQuery.module';
import { ReconQueryService } from './reconQuery/reconQuery.service';
import { ReconQueryController } from './reconQuery/reconQuery.controller';
#Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/backend-app', { useNewUrlParser: true }),
ReconQueryModule
],
controllers: [AppController, ReconQueryController],
providers: [AppService, ReconQueryService], // <-- this causes the error
})
export class AppModule {}
#InjectModel() is provided by calling MongooseModule.forFeature(...) on a certain #Module(). ReconQueryService in ReconQueryModule is fine because that's where you have MongooseModule.forFeature() called so #InjectModel() is provided properly. However, in AppModule, you don't have MongooseModule.forFeature() so Nest cannot resolve the #InjectModel() for ReconQueryService.
Check if you really need to use ReconQueryService in AppModule (services and controllers declared in AppModule). If you don't, then remove ReconQueryService from providers array. If you do, then go to ReconQueryModule and do the following:
import { Module } from '#nestjs/common';
import { ReconQueryController } from './reconQuery.controller';
import { ReconQueryService } from './reconQuery.service';
import { MongooseModule } from '#nestjs/mongoose';
import { ReconQuerySchema } from './schemas/reconQuery.schema';
#Module({
imports: [
MongooseModule.forFeature([{ name: 'ReconQuery', schema: ReconQuerySchema }])
],
controllers: [ReconQueryController],
providers: [ReconQueryService],
exports: [ReconQueryService] // <-- add this line
})
export class ReconQueryModule {}
exported things will be available to use outside of the module they're provided in. Just import that module somewhere else.

Categories