회원가입 중복처리 문제 해결 및 원인 해석(?)

캡틴 노드랭크·2021년 7월 2일
2

NodeJS

목록 보기
3/12

이전에 회원가입을 할 경우 "이미 사용중인 이메일입니다." 라며 응답코드 400과 함께 Json으로 응답받는다.

문제의 회원가입 로직을 다시 한번 보자

module, register

exports.register = async (req, res) => {
  const { errors, isValid } = registerValidator(req.body);

  let { email, username, password } = req.body;

  if (!isValid) {
    return res.status(400).json(errors);
  }

  const emailExists = await User.findOne({ Where: { email: email } });
  console.log(emailExists);
  if (emailExists) {
    return res.status(400).json({ message: "이미 사용중인 이메일입니다." });
  }
  const salt = await bcrypt.genSalt(10);
  const hashedPassword = await bcrypt.hash(password, salt);

  const newUser = {
    username: username,
    email: email,
    password: hashedPassword,
  };

  User.create(newUser)
    .then((save) => {
      res.status(200).json({ status: "Success", new_user_id: save.id });
    })
    .catch((err) => res.status(500).json({ message: err + "잘안됩니다." }));

이 코드에서 첫 회원가입을 시도하는 경우 다행이 정상적으로 진행된다.

문제는 새로 작성된 이메일의 중복을 검사하는 로직이 담긴 변수 emailExists는 새로운 계정을 생성해도 여전히 엉뚱한 레코드만 조회하고있다.

sequelize에서 findOne() 단순히 하나의 데이터를 조회하는 기능이다. 접근 방법이 잘못됬나 싶다..
그래서 이번엔 복수의 데이터를 조회하는 findAll()을 사용해봤다.

const emailExists = await User.findAll({ Where: { email: email } });
  console.log(emailExists);
  if (emailExists) {
    return res.status(400).json({ message: "이미 사용중인 이메일입니다." });
  }

여전하다.. 대체 뭐가문제일까

sequelize 공식 문서는 워낙 제공하는 기능이 많다보니 많이 난잡하고 어지러운데다 설명조차 불친절하다. 스택오버플로우도 명쾌한 설명이 보이지않아서 결국에는 findOneCreate()를 사용해보기로 했다.

findOneCreate()where로 조건을 걸어놓으면 특정 데이터가 존재하는지 찾고 없으면 생성하는 명령어이다.

공식문서에 따르면 아래와 같은 예시로 작성해준다

const [user, created] = await User.findOrCreate({
  where: { username: 'sdepold' },
  defaults: {
    job: 'Technical Lead JavaScript'
  }
});
console.log(user.username); // 'sdepold'
console.log(user.job); // This may or may not be 'Technical Lead JavaScript'
console.log(created); // The boolean indicating whether this instance was just created
if (created) {
  console.log(user.job); // This will certainly be 'Technical Lead JavaScript'
}

findOrCreate()를 쓴다면 React-hook에서 비구조화 할당을 사용한 useState() 작성법과 유사한 것 같다.

그래서 최종 답안은 아래와 같다.


  // const emailExists = await User.findAll({ Where: { email: email } });
  // //   console.log(emailExists);
  // if (emailExists) {
  //   return res.status(400).json({ message: "이미 사용중인 이메일입니다." });
  // }
  const salt = await bcrypt.genSalt(10);
  const hashedPassword = await bcrypt.hash(password, salt);

  const newUser = {
    username: username,
    email: email,
    password: hashedPassword,
  };

  User.findOrCreate({ where: { email: email }, defaults: newUser })
    .then(([save, created]) => {
      if (!created) {
        return res.status(400).json({ message: "이미 사용중인 이메일입니다." });
      } else {
        console.log([save, created]);
        res.status(200).json({ status: "Success", new_user_id: save.id });
      }
    })
    .catch((err) => res.status(500).json({ message: err + "잘안됩니다." }));

위의 코드의 중복 처리하는 부분을 주석처리한 뒤에 예제와 같이 작성해주었다.

공식문서 예제와는 다르게 프로미스로 전달받은.then()의 인자를 배열안에 담아줬는데 만약 담지 않을 경우 상태응답코드 400을 받는대신 새로운 계정이 생성되는 기이한 현상을 볼 수 있다.


결과는 성공적으로 나왔다.

sequelize 여전히 이해하기 어렵지만 아무튼 잘되서 좋다.

profile
다시 처음부터 천천히... 급할필요가 없다.

0개의 댓글