이전에 회원가입을 할 경우 "이미 사용중인 이메일입니다." 라며 응답코드 400과 함께 Json으로 응답받는다.
문제의 회원가입 로직을 다시 한번 보자
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
여전히 이해하기 어렵지만 아무튼 잘되서 좋다.