로컬 채팅 앱 (3) - User SignUp , SignIn

적어야 머리에 남는다! ·2021년 11월 19일
0

로컬 채팅 앱

목록 보기
3/3

User Sign up

provider : 제품 제공
controller : 제품 사용

local

우선 이메일과 비번을 입력하여 사이트 내에서 직접 가입하는 경우의 signup signIn api를 만들기로 했다.

로직 순서
user.controller -> user.service -> user.repository

user.controller

우선 user.controller에서 부터 로직은 시작이 된다 (정확히는 module부터지만)

처음 @controller에서 root routing 다음 향할 routing주소로 users를 지정한다. 이후 각 api 별로 @Post, @Get 등을 사용해서 api를 만든다.

그리고 userService를 constructor에 지정해서 클래스 내부에서 사용할 수 있도록 지정을 해준다.

POST : ~~/users/signUp로 요청이 왔을 때의 api를 작성하면 위와 같다.

우선 post에 필요한 바디를 받기 위해 @Body를 이용하고 validationPipe를 지정해서 들어갈 데이터에 대해서 검사를 진행한다. 그리고 들어갈 데이터는 별도의 dto로 만들어서 타입을 받는다.

class validator를 통해서 간단하게 타입 및 제약사항을 검사할 수 있다. ( @IsString, @IsNotEmpty 등)


만일 위에처럼 타입이 맞지 않는다면 class validator가 해당하는 에러메시지를 발송한다.

검사가 통과한 자료는 dto의 형태로 userSevice에 singUp함수로 이동한다.

user.service.ts

user service에서는 signUp함수를 정의해주면 되는데 signUp함수는 다시 repository에서 db관련 로직을 처리하게 된다.

이 과정을 진행을 할 때 에러를 마주했다.

Nest can't resolve dependencies of the Userservice Error

Nest can't resolve dependencies of the Userservice라는 문구의 에러였다. 특히 디버깅을 위해서는 Please make sure the argumenet UserRepository at index [0] is availabe in the UserModule context 에서 UserRepository at index [0]가 어디를 나타내는지 아는 것이 중요했다.



@Injectable()
export class UsersService {
  constructor(private userRepository: UserRepository) {}
}

블로그 게시글을 참조하고 나니 Userservice첫번째 constructorUserRepository가 문제임을 알게 되었다.

사실 위에 에러 경고문에도 나와있었다. dependencies of the Userservice 이렇게!!

그래서 이것을 해결하기 위해 Provider의 개념의 집중을 해보기로 했다. Provider는 말그래도 공급자이다. 어떤 개념 서비스 등을 이용을 하려고 하는데 이 것을 가져오지 못하기 때문에 발생하는 에러인 것이다.

그러면 user.module에서 providers가 잘 설정이 안된 것이었다.

확인을 해보니 providersUserRepository가 없었다!

UserRepository를 사용하고 싶은떼 providers에 없기 때문에 가져올 수 없던 것이었다.

위와같이 추가를 해주고 나면 에러가 해결되는 것을 알 수 있다!


User.repository.ts

다음으로 repository를 정의해서 db에 접근하는 작업을 관리하기로 했다.

//* user.repository.ts

@Injectable()
export class UserRepository {
  constructor(@InjectModel(User.name) private userModel: Model<User>) {}

  //* signUp User
  async createUser(createUserDto: CreateUserDto): Promise<void> {
    const { email, password, address, nickName } = createUserDto;

    const isUserExist = await this.userModel.exists({ email });

    if (isUserExist) {
      throw new UnauthorizedException('duplicated user');
    }
    const salt = await bcrypt.genSalt();
    const hashedPassword = await bcrypt.hash(password, salt);

    try {
      this.userModel.create({
        email,
        password: hashedPassword,
        address,
        nickName,
      });
    } catch (error) {
      if (error) {
        console.log(error);
      }
    }
  }
}

repository constructor
참고 링크

user.repostiory 만드는 법

위와같은 방식으로 모델을 Inject하는 방식으로 Repository를 만들 수 있다. 다만 User.name부분이 왜 User클래스 자체로는 안되는지 궁금했다.

그래서 User를 넣고 돌려봤을 때 어떤 결과가 나오는지 보았다.

그랬더니 타입이 string이 아니라서 에러가 나온다고 했다.

console.log (User.name) 
console.log(typeof User.name)

콘솔을 통해서 확인을 해보니 다음과 같은 결과가 나왔다.

User.name은 User이고 string타입이었다. 그래서 매핑을 할 때 요구하는 스트링 타입은 만족하면서 어떤 모델인지를 특정할 수 있었던 것이다.

로직 정리

궁금증은 해결을 했고 이제 로직을 조금 더 정리를 해야겠다

dto를 통해서 받은 자료들 안에 있는 key값들을 구조분해할당을 이용해 각 변수에 할당을 해준다.

그리고 기존 email과의 중복여부를 파악하기 위해 this.userModel.exists({})를 이용해서 확인을 한다.

만약 isUserExist가 true 이면 duplicate user 에러를 return 한다.

비밀번호 hashing

중복된 유저가 없다면 bcrypt를 통해 salt를 생성한 후 그 saltpassword를 합친 값을 해쉬함수를 통해 hashedpassword를 만든다. 이렇게 함으로써 rainbow table로 비밀번호를 찾아내는 것을 어렵게 만든다.

이제 해쉬된 패스워드와 같이 만들어진 변수들을 userModel에 삽입을 한다.

그리고 만약 이 과정에서 error가 발생하면 NestJs에 Logger를 이용해서 log를 남긴다.


Google singUp

Kakao loginUp

SignIN

profile
기록을 통해 한 걸음씩 성장ing!

0개의 댓글