NestJS 依赖注入 – 从解析器的构造函数中删除垃圾

huangapple go评论68阅读模式
英文:

NestJS dependency injection - delete garbage from constructor in resolver

问题

我已经看到你的代码并了解了你的问题。你的问题似乎与依赖注入有关,特别是在NestJS中如何正确注入依赖。

首先,你尝试使用UserRepoSymbol来提供UserPostgresql,然后在UserService中注入它,这是一个正确的做法。但是,根据你的错误消息,问题可能出在配置文件的导入和环境变量的设置上。

确保以下几点:

  1. 确保你的.env文件路径正确,并且文件包含所需的环境变量。你可以在 dotenv.config({ path: ENV_FILE_PATH }) 这一行之后添加 console.log(process.env) 来检查是否成功加载了环境变量。

  2. 确保 UserRepoSymbol 的值与你的提供者名称一致。在你的模块中,你提供了一个名称为Object的提供者,但在注入时使用的是 UserRepoSymbol。确保它们匹配。

  3. 检查 UserPostgresql 是否正确导入并在 providers 数组中添加到 UserModule 中。

如果你仍然遇到问题,可以提供更多关于错误消息的信息,以便我能够提供更具体的帮助。

英文:

So I have been working on a NestJs+Graphql+Postgresql application using ddd architecture. And now it just adds user to a database.

I have the following user.resolver in the presentation layer:

@Resolver(of => UserBaseWithPassword)
export class UserResolver {
    private readonly userApplication: UserApplication
    constructor(private readonly userRepo: UserPostgresql) {
        const userService = new UserService(userRepo)
        this.userApplication = new UserApplication(userService)
    }
    
    @Query(returns => String)
    users() : string {
        return "";
    }

    @Mutation(returns => String)
    async createUser(@Args('createUserDTO') createUserWithPasswordDTO: CreateUserWithPasswordDTO): Promise<string> {
        return await this.userApplication.create(createUserWithPasswordDTO=createUserWithPasswordDTO)
    }

}

It works fine, but I need to get rid of garbage in the constructor.
Here is my application layer's
user.ts :

export class UserApplication{
    constructor(private userService: UserService) {}

    async create(createUserWithPasswordDTO: CreateUserWithPasswordDTO): Promise<string> {
        return await this.userService.create(createUserWithPasswordDTO=createUserWithPasswordDTO);
    }
}

In the domain layer i have user.service.ts :

@Injectable()
export class UserService {
    constructor(private readonly userRepo: IUserRepo) {}

    async create(createUserWithPasswordDTO: CreateUserWithPasswordDTO): Promise<string> {
        this.validateEmail(createUserWithPasswordDTO.email)
        this.validatePassword(createUserWithPasswordDTO.password)
        try{
            createUserWithPasswordDTO.password = await this.hashPassword(createUserWithPasswordDTO.password);
            return await this.userRepo.create(createUserWithPasswordDTO);
        }catch(e){
            throw new Error("DEFAULT_USER_ERROR"+e)
        }
    }

    private async hashPassword(password: string): Promise<string> {
        const saltRounds = process.env.PASSWORD_SALT_ROUNDS;
        return await bcrypt.hash(password, saltRounds);;
    }

    private validateEmail(email: string): boolean {
        if(email.length < MIN_EMAIL_LENGTH)
            throw new Error(EMAIL_MIN_LENGTH_TEXT)
        if(email.length > MAX_EMAIL_LENGTH)
            throw new Error(EMAIL_MAX_LENGTH_TEXT)
        if(!EMAIL_REGEX.test(email))
            throw new Error(EMAIL_REGEX_TEXT)
        return true;
    }

    private validatePassword(password: string): boolean {
        if(password.length < MIN_PASSWORD_LENGTH || password.length > MAX_PASSWORD_LENGTH)
            throw new Error(PASSWORD_LENGTH_ERROR_TEXT)
        if(!PASSWORD_HAS_NUMBER_REGEX.test(password))
            throw new Error(PASSWORD_NOT_INCLUDES_NUMBER_TEXT)
        if(!PASSWORD_HAS_LETTER_REGEX.test(password))
            throw new Error(PASSWORD_NOT_INCLUDES_LETTER_TEXT)
        return true;
    }
}

and an Interface user.repo :

import { CreateUserWithPasswordDTO } from "./dtos/create-user.dto";

export interface IUserRepo  {    
    create(createUserWithPasswordDTO: CreateUserWithPasswordDTO): Promise<string>
}

And lastly, in the infrustructure layer I have repo.ts, that implements interface UserRepo :

@Injectable()
export class UserPostgresql implements IUserRepo{
    constructor(@InjectDataSource() private dataSource: DataSource) {}
    async create(createUserWithPasswordDTO: CreateUserWithPasswordDTO): Promise<string> {
        const parameters = [uuidv4(), createUserWithPasswordDTO.email, createUserWithPasswordDTO.password]
        const reply = await this.dataSource.query(CREATE_USER, parameters)
        return reply[0].id
    }
}

I mention all above in the user.module :

import * as dotenv from 'dotenv';

const ENV_FILE_PATH = './ci/postgres/.env'
dotenv.config({path: ENV_FILE_PATH});

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [],
  providers: [ 
    Object,
    UserPostgresql,
    UserService,
    UserApplication,
    UserPostgresql,
    UserResolver
  ]
})
export class UserModule {}

I write Object in the @Module, because program doesn't compile without it which is also an issue.

I tried to write in user.module something like

{
      provide: UserRepoSymbol,
      useClass: UserPostgresql,
},

then changing constructor in the user.service to :

constructor(@Inject(UserRepoSymbol) private readonly userRepo: IUserRepo) {}

and also changing the user.resolver's constructor just to:


constructor(private readonly userApplication: UserApplication) {}

but it seems not to work and i get an error :

TypeError: Cannot read properties of undefined (reading 'create')
    at UserApplication.create (C:\path\api-service\src\application\user.ts:8:39)
    at UserResolver.createUser (C:\path\src\presentation\user\user.resolver.ts:20:43)...

答案1

得分: 0

我忘记了在 user.application 中使用 @Injectable 装饰器。

英文:

I forgot @Injectable decorator in user.application

huangapple
  • 本文由 发表于 2023年6月25日 22:07:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76550803.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定