i'm facing an issue with NestJS :
"[Nest] 5068 - 08/11/2021, 3:12:02 PM ERROR [ExceptionHandler] Nest can't resolve dependencies of the AppService (?). Please make sure that the argument UserRepository at index [0] is available in the AppModule context."
I tried to add AppService in the imports with no luck.
How to evade this error?
app.module.ts :
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { User } from './user.entity';
#Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'password',
database: 'test',
entities: [User],
synchronize: true,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
app.controller.ts :
import { Body, Controller, Get, Post } from '#nestjs/common';
import { AppService } from './app.service';
import * as bcrypt from 'bcrypt';
#Controller('api')
export class AppController {
constructor(private readonly appService: AppService) {
}
#Post('register')
async register(
#Body('name') name: string,
#Body('email') email: string,
#Body('password') password: string,
#Body('phone') phone: string,
) {
const hashedPassword = await bcrypt.hash(password, 12);
return this.appService.create({
name,
email,
password: hashedPassword,
phone,
})
}
}
app.service.ts :
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
#Injectable()
export class AppService {
constructor(
#InjectRepository(User) private readonly userRepository: Repository<User>
) {
}
async create(data: any): Promise<User> {
return this.userRepository.save(data)
}
}
user.entiry.ts :
import { Column, Entity, PrimaryColumn } from "typeorm";
#Entity('users')
export class User {
#PrimaryColumn()
id: number;
#Column()
name: string;
#Column()
email: string;
#Column()
phone: string;
#Column()
password: string;
}
Thank you
You need to add TypeormModule.forFeature([User]) to your imports in your AppModule to set up the #InjectRepository(User) that you make use of. With the TypeORM module, forRoot/Async is for database connection and general TypeORM configuration, forFeature is for dynamic provider setup
Related
I want to use configService inside a DTO
my app.module.ts is
...
Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ['.env', '.env.dev', '.env.stage', '.env.prod'], //if a variable is found in multiple files, the first one takes precedence.
load: [
databaseConfig,
authConfig,
appConfig,
mailConfig,
],
}),
...
And I want to use configService in my DTO like:
import { ApiProperty } from '#nestjs/swagger';
import { MaxLength, IsNotEmpty, IsEmail, IsString } from 'class-validator';
import { ConfigService } from '#nestjs/config';
let configService: ConfigService;
export class LoginDto {
#IsEmail()
#ApiProperty({ example: configService.get('auth.dummyEmail') })
readonly email: string;
#IsNotEmpty()
#IsString()
#MaxLength(60)
#ApiProperty({ example: 'secret' })
readonly password: string;
}
I get this error:
#ApiProperty({ example: configService.get('auth.dummyEmail') })
import { ApiProperty } from '#nestjs/swagger';
import { MaxLength, IsNotEmpty, IsEmail, IsString } from 'class-validator';
import { ConfigService } from '#nestjs/config';
import appConfig from '../../config/app.config';
const configService = new ConfigService({ app: appConfig() });
export class LoginDto {
#IsEmail()
#ApiProperty({ example: configService.get('app.auth.dummyEmail') })
readonly email: string;
#IsNotEmpty()
#IsString()
#MaxLength(60)
#ApiProperty({ example: 'secret' })
readonly password: string;
}
The admin-bro-nestjs repository contains a comprehensive example with example with mongoose. But I need use it with typeorm and postgres.
I tried to adapt this example for typeorm:
// main.ts
import AdminBro from 'admin-bro';
import { Database, Resource } from '#admin-bro/typeorm';
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
AdminBro.registerAdapter({ Database, Resource });
const bootstrap = async () => {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
and
// app.module.ts
import { Module } from '#nestjs/common';
import { AdminModule } from '#admin-bro/nestjs';
import { TypeOrmModule, getRepositoryToken } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserEntity } from './user/user.entity';
#Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'password',
database: 'database_test',
entities: [UserEntity],
synchronize: true,
logging: false,
}),
AdminModule.createAdminAsync({
imports: [
TypeOrmModule.forFeature([UserEntity]),
],
inject: [
getRepositoryToken(UserEntity),
],
useFactory: (userRepository: Repository<UserEntity>) => ({
adminBroOptions: {
rootPath: '/admin',
resources: [
{ resource: userRepository },
],
},
auth: {
authenticate: async (email, password) => Promise.resolve({ email: 'test' }),
cookieName: 'test',
cookiePassword: 'testPass',
},
}),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
But on application start I get the following error:
NoResourceAdapterError: There are no adapters supporting one of the resource you provided
Does anyone have any experience putting all these libraries together?
I also got NoResourceAdapterError: There are no adapters supporting one of the resource you provided when I tried to integrate AdminBro with NestJS/Express/TypeORM (though I'm using MySQL instead Postgres). The solution posted in the admin-bro-nestjs Github issue which links to this question didn't help me.
The cause of NoResourceAdapterError for me simply was that UserEntity didn't extend BaseEntity. NestJS/TypeORM seems to work fine without extending BaseEntity but apparently it is required for AdminBro. You can see it used in the examples of the AdminBro TypeORM adapter documentation.
Here is an example which works for me.
// user.entity
import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from 'typeorm';
#Entity()
export class UserEntity extends BaseEntity{
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
}
// app.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AdminModule } from '#admin-bro/nestjs';
import { Database, Resource } from '#admin-bro/typeorm';
import AdminBro from 'admin-bro'
AdminBro.registerAdapter({ Database, Resource });
#Module({
imports: [
TypeOrmModule.forRoot({
// ...
}),
AdminModule.createAdmin({
adminBroOptions: {
resources: [UserEntity],
rootPath: '/admin',
},
})
],
// ...
})
I am a newbie in NestJs world. As far as I know, I imported everything needed in the JwtStrategy. I don't know where it went wrong. Can somebody help me with this?
As far as I referred to documetation, Whenever we want to use any entity in a module, we should import that entity in the imports field in the #Module() decorator. I did it.
jwt.strategy.ts
import { Injectable, UnauthorizedException } from "#nestjs/common";
import { PassportStrategy } from "#nestjs/passport";
import { Strategy, ExtractJwt } from "passport-jwt";
import { InjectRepository } from "#nestjs/typeorm";
import { Repository } from "typeorm";
import { UserEntity } from "src/entities/user.entity";
import { AuthPayload } from "src/common/dtos/user.dto";
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
#InjectRepository(UserEntity)
private userRepo: Repository<UserEntity>
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRETKEY
});
}
async validate(payload: AuthPayload): Promise<UserEntity> {
const { username } = payload;
const user = this.userRepo.findOne({ where: { username: username } });
if(!user) {
throw new UnauthorizedException();
}
return user;
}
}
auth.module.ts
import { Module } from '#nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { TypeOrmModule } from '#nestjs/typeorm';
import { UserEntity } from 'src/entities/user.entity';
import { JwtModule } from '#nestjs/jwt';
import { PassportModule } from '#nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
#Module({
imports: [
TypeOrmModule.forFeature([UserEntity]),
JwtModule.register({
secret: process.env.SECRETKEY,
}),
PassportModule.register({
defaultStrategy: 'jwt'
})
],
providers: [AuthService, JwtStrategy],
controllers: [AuthController],
exports: [PassportModule, JwtStrategy]
})
export class AuthModule {}
user.entity.ts
import { Entity, Column, OneToMany, JoinTable, BeforeInsert } from "typeorm";
import { AbstractEntity } from "./abstract-entity.abstract";
import { IsEmail } from "class-validator";
import { Exclude, classToPlain } from "class-transformer";
import * as bcrypt from "bcryptjs";
import { CategoryEntity } from "./category.entity";
import { ArticleEntity } from "./article.entity";
#Entity('User')
export class UserEntity extends AbstractEntity {
#Column({
type: "varchar",
length: 80
})
fullName: string;
#Column({
type: "varchar",
unique: true
})
#IsEmail()
email: string;
#Column({
type: "varchar",
unique: true
})
username: string;
#Column({
type: "varchar"
})
#Exclude()
password: string;
#Column({
default: null,
nullable: true
})
avatar: string | null;
#Column({
type: "varchar",
unique: true
})
phoneNumber: string;
#Column({
type: "boolean",
default: false
})
isAdmin: boolean;
#Column({
type: "boolean",
default: false
})
isStaff: boolean;
#Column({
type: "boolean",
default: false
})
isEmailVerified: boolean;
#OneToMany(type => CategoryEntity, category => category.createdBy)
#JoinTable()
categories: CategoryEntity[];
#OneToMany(type => ArticleEntity, article => article.createdBy)
#JoinTable()
articles: ArticleEntity[];
#BeforeInsert()
async hashPassword() {
this.password = await bcrypt.hash(this.password, 10);
}
async comparePassword(attempt: string): Promise<boolean> {
return await bcrypt.compare(attempt, this.password);
}
toJSON(): any {
return classToPlain(this);
}
}
app.module.ts
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from "#nestjs/typeorm";
import { APP_FILTER, APP_INTERCEPTOR } from '#nestjs/core';
import {
DatabaseConnectionService
} from "./utils/database-connection.service";
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { ArticlesModule } from './articles/articles.module';
import { HttpExceptionFilter } from './common/exception-filters/http-exception.filter';
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
import { CategoryModule } from './category/category.module';
#Module({
imports: [
TypeOrmModule.forRootAsync({
useClass: DatabaseConnectionService
}),
AuthModule,
UsersModule,
ArticlesModule,
CategoryModule,
],
controllers: [AppController],
providers: [
// {
// provide: APP_INTERCEPTOR,
// useClass: ResponseInterceptor
// },
{
provide: APP_FILTER,
useClass: HttpExceptionFilter
},
AppService
],
})
export class AppModule {}
database-connection.service.ts
import { Injectable } from "#nestjs/common";
import { TypeOrmOptionsFactory, TypeOrmModuleOptions } from "#nestjs/typeorm";
import { truncate } from "fs";
#Injectable()
export class DatabaseConnectionService implements TypeOrmOptionsFactory {
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: "mysql",
host: process.env.HOST,
port: parseInt(process.env.PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DATABASE,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
dropSchema: true,
autoLoadEntities: true,
logger: "simple-console"
};
}
}
The Error is as follows:
Based on your error, somewhere you have JwtStrategy in your imports array. If you need the JwtStrategy you should instead import the AuthModule, as providers should only be in the providers array and should never be in imports.
Consider to move to Active Record pattern. All what you need to do is just to let your AbstractEntity extends BaseEntity of TypeOrm.
You can remove all typeorm features imports like:
TypeOrmModule.forFeature([UserEntity])
and all dependency injections for repository like:
#InjectRepository(UserEntity)
private userRepo: Repository<UserEntity>
Just use the entity class for querying:
const user = await UserEntity.findOne({ where: { username } });
I'm having issues adding a second entity into my Nest project. It works fine with just one entity Video, but now when I have added another User, I get the error No repository for "User" was found. Looks like this entity is not registered in current "default" connection? on compilation.
What am I doing wrong here?
database.module.ts
import { Module } from "#nestjs/common";
import { TypeOrmModule } from "#nestjs/typeorm";
import { ConfigModule } from "../config/config.module";
import { ConfigService } from "../config/config.service";
import { Video } from "../videos/video.entity";
import { User } from "../auth/user.entity";
#Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
type: 'postgres' as 'postgres',
host: configService.dbHost,
port: configService.dbPort,
username: configService.dbUsername,
password: configService.dbPassword,
database: configService.dbName,
entities: [Video, User],
synchronize: true
}),
inject: [ConfigService]
})
]
})
export class DatabaseModule {}
user.entity.ts
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm";
Entity()
export class User extends BaseEntity {
#PrimaryGeneratedColumn()
id: number
#Column()
username: string;
#Column()
password: string;
}
Sorry.. typo by me. Forgot to decorate the entity properly. Should be #Entity()
I'm trying to figure out how the "Repository Pattern" of TypeOrm in Nest works. I would like to have a resources file in which a local and a remote file hold the different entites, controllers, modules etc. See screenshot
When the app is building I`m getting the following error:
[Nest] 3186 - 11/19/2018, 10:44:43 PM [ExceptionHandler] No repository for "Project" was found. Looks like this entity is not registered in current "default" connection? +1ms
From the Nest and TypeORM documentation I can triangulate, that I have to tell the application where it can find the entities or at least this is what I believe the error is trying to tell me.
I'm using a .env to pull the config for TypeORM in:
TYPEORM_CONNECTION = postgres
TYPEORM_HOST = localhost
TYPEORM_USERNAME = xyz
TYPEORM_PASSWORD = xyz
TYPEORM_DATABASE = xyz
TYPEORM_PORT = 5432
TYPEORM_SYNCHRONIZE = true
TYPEORM_LOGGING = true
TYPEORM_ENTITIES = src/server/**/**.entity{.ts,.js}
app.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AngularUniversalModule } from './modules/angular-universal/angular-universal.module';
import { JiraService } from './services/jira.service'
// modules
import { ProjectModule } from './resources/local/project/project.module'
// sync
import {ProjectsSync} from './sync/projects.sync'
#Module({
imports: [
ProjectModule,
TypeOrmModule.forRoot(),
AngularUniversalModule.forRoot(),
],
controllers: [],
providers:[JiraService, ProjectsSync],
})
export class ApplicationModule {}
project.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { ProjectService } from './project.service';
import { ProjectController } from './project.controller';
import { Project } from './project.entity';
#Module({
imports: [TypeOrmModule.forFeature([Project])],
providers: [ProjectService],
controllers: [ProjectController],
})
export class ProjectModule {}
project.service.ts
import { Injectable, Inject } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { Project } from './project.entity';
#Injectable()
export class ProjectService {
constructor(
#InjectRepository(Project)
private readonly projectRepository: Repository<Project>,
) {}
async findAll(): Promise<Project[]> {
return await this.projectRepository.find();
}
}
project.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
#Entity()
export class Project {
#PrimaryGeneratedColumn()
id: number;
#Column({ length: 500 })
name: string;
}
project.controller.ts
import { Controller, Get } from '#nestjs/common';
import { ProjectService } from './project.service';
import { Project } from './project.entity';
#Controller('project')
export class ProjectController {
constructor(private readonly projectService: ProjectService) {}
#Get()
findAll(): Promise<Project[]> {
return this.projectService.findAll();
}
}
Just a wild guess, have you tried:
TYPEORM_ENTITIES = ./server/**/**.entity{.ts,.js}
And/or switching the imports in app.module.ts putting the TypeOrmModule first:
#Module({
imports: [
TypeOrmModule.forRoot(),
ProjectModule,
AngularUniversalModule.forRoot(),
],
controllers: [],
providers:[JiraService, ProjectsSync],
})
export class ApplicationModule {}
In your .env file change
TYPEORM_ENTITIES = src/server/**/**.entity{.ts,.js}
to
TYPEORM_ENTITIES = /../**/*.entity.{js,ts}
in your app.module use:
const typeOrmConfig: TypeOrmModuleOptions = {
type: process.env.TYPEORM_CONNECTION,
host: process.env.TYPEORM_HOST,
port: process.env.TYPEORM_PORT,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE,
synchronize: process.env.TYPEORM_SYNCHRONIZE,
logging: process.env.TYPEORM_LOGGING,
entities: [__dirname + process.env.TYPEORM_ENTITIES]
}
#Module({
imports: [
TypeOrmModule.forRoot(typeOrmConfig),
ProjectModule,
AngularUniversalModule.forRoot(),
],
controllers: [],
providers:[JiraService, ProjectsSync],
})
export class ApplicationModule {}