Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject service into pipe in NestJs

Tags:

node.js

nestjs

I'm trying to inject a service in a pipe. I'm using pipe (signupPipe) in a controller, POST method.

// signup.pipe.ts

import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
import * as bcrypt from 'bcrypt';
import { UserService } from './user.service'

@Injectable()
export class SignupPipe implements PipeTransform<any> {
    constructor(private userService: UserService) { }

    async transform(value: any) {
        // validate password
        const areTheSame = this.validatePassword(value.password, value.passwordRepeat);

        if (!areTheSame) {
            throw new BadRequestException("Password are not the same.");
        }

        // check if account exists
        const isExists = await this.userService.findOne(value.email)

        if (isExists) {
            throw new BadRequestException("Account with provided email already exists.");
        }

        // create encrypted password
        const signupData = {...value}
        signupData.password = await bcrypt.hash(value.password, 10)

        return signupData
    }

    private validatePassword(password: string, passwordRepeat: string): boolean {
        return password === passwordRepeat
    }
}

My controller:

@Controller("user")
export class UserController {
    constructor(private userService: UserService, private signupPipe: SignupPipe) { }
    
    @Post("signup")
    async signup(@Body(this.signupPipe) createUserDto: CreateUserDto) {
        return await this.userService.signup(createUserDto)
    }
}

User module:

@Module({
    imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],
    controllers: [UserController],
    providers: [
        UserService
    ],
    exports: [UserService]
})
export class UserModule { }

How to correctly inject a pipe which includes another service injected by DI? Now it doesn't work, error:

Nest can't resolve dependencies of the UserController (UserService, ?). Please make sure that the argument SignupPipe at index [1] is available in the UserModule context.

Does my pipe is correct? I'm not sure, because it does a few things (validate pwd/repeat, check if acc exists, encrypt pwd) - so probably it breaks SOLID rule (SRP) - so should I split these 3 roles into 3 separated pipes?

Thanks.

like image 633
Dominik Avatar asked Dec 22 '22 17:12

Dominik


1 Answers

You can't use class members inside of decorators, it's a language constraint of typescript. However, you can allow Nest to do the DI work for you by using @Body(SignupPipe) on it's own. Nest will read the constructor of the pipe and see what needs to be injected into it.

@Controller("user")
export class UserController {
    constructor(private userService: UserService, ) { }
    
    @Post("signup")
    async signup(@Body(SignupPipe) createUserDto: CreateUserDto) {
        return await this.userService.signup(createUserDto)
    }
}
like image 124
Jay McDoniel Avatar answered Dec 31 '22 08:12

Jay McDoniel