★ 개인 프로젝트(spa_blog)에서 게시글 / 댓글 API
1) 회원가입 POST(/signup)
const { nickname, password, confirmPassword } = req.body;
let nicknameReg = new RegExp(/^[\w]{3,12}$/g);
if (!nickname || !password || !confirmPassword) {
res.status(412).json({
success: false,
errorMessage: "닉네임, 비밀번호, 비밀번호 확인을 전부 입력해 주세요.",
});
return;
}
if (!nicknameReg.test(nickname)) {
res.status(412).json({
success: false,
errorMessage: "닉네임은 3 ~ 12자리이면서 알파벳이나 숫자로만 구성해주세요.",
});
return;
}
if (password.length < 4 || password.includes(nickname)) {
res.status(412).json({
success: false,
errorMessage: "패스워드는 4자리이상이고 닉네임과 같은 값이 포함이 되면 안됩니다.",
});
return;
}
if (password !== confirmPassword) {
res.status(412).json({
success: false,
errorMessage: "패스워드와 패스워드확인이 다릅니다.",
});
return;
}
=> 정규형 사용해서 3~12자리 숫자와 문자만 포함되도록 지정해서 아이디에 Validation Check하고 요구사항에 필요한 유효성 검사도 전부 추가했음
2) 로그인 POST(/login)
const jwt = require("jsonwebtoken");
const { nickname, password } = req.body;
const user = await User.findOne({ nickname });
if (!user || user.password !== password) {
res.status(412).json({
success: false,
errorMessage: "닉네임 또는 패스워드를 확인해주세요. ",
});
return;
}
const token = jwt.sign({ userId: user.userId }, "secret-login-key", { expiresIn: "1h" });
res.cookie("Authorization", `Bearer ${token}`);
=> 해당 닉네임이 없거나 비밀번호가 다르면 반환되는 유효성 검사 후 토큰을 만들어서 저장이 되도록 구현(이 때, 1시간으로 만료 시간을 정함)
3) 게시글 등록하기POST 수정(/posts)
const user = res.locals.user;
const userNickname = res.locals.userNickname;
const { title, content } = req.body;
if (!title || !content)
return res
.status(412)
.json({ success: false, errorMessage: "게시글의 정보가 입력되지 않았습니다." });
await Post.create({ userId: user._id, nickname: userNickname, title, content });
=> jsonwebtoken으로 저장되어 있는 값에서 검증 후 검증에 문제가 없다면 res.locals.user와 res.locals.userNickname을 가져와 게시글을 저장할 때 해당 로그인이 되어 있는 정보도 같이 저장하도록 수정
4) 게시글 수정PUT 수정(/posts/:postid)
const { postId } = req.params;
const { userId } = res.locals.user;
const { title, content } = req.body;
const existPost = await Post.findById(postId);
if (!existPost)
return res
.status(404)
.json({ success: false, errorMessage: "해당 게시글을 찾을 수 없습니다." });
if (userId !== existPost.userId)
return res
.status(403)
.json({ success: false, errorMessage: "게시글 수정 권한이 존재하지 않습니다." });
if (!title || !content)
return res
.status(412)
.json({ success: false, errorMessage: "게시글 제목이나 내용이 빈 내용인지 확인해 주세요" });
=> 현재 로그인 되어 있는 값과 저장된 게시글의 userId를 비교해 같으면 수정할 수 있도록 하고 다르다면 수정을 할 수없도록 수정했음(삭제도 동일하게 구현 / 댓글도 게시글과 유사하게 구현했음)
5) middlewares폴더에 auth-middleware.js를 통해 미들웨어를 만들어서 로그인 시, 토큰이 저장이 되도록 구현
const { Authorization } = req.cookies;
const [authType, authToken] = (Authorization ?? "").split(" ");
if (authType !== "Bearer" || !authToken) {
res.status(403).json({
success: false,
errorMessage: "로그인 후에 이용할 수 있는 기능입니다.",
});
return;
}
const { userId } = jwt.verify(authToken, "secret-login-key");
const user = await User.findById(userId);
if (!user) {
res.clearCookie("Authorization");
res.status(403).json({ success: false, errorMessage: "토큰 사용자가 존재하지 않습니다." });
}
res.locals.user = user;
res.locals.userNickname = user.nickname;
=> 로그인 시, cookie-parser미들웨어를 통해 해당 토큰을 보내 검증 후 로그인한 정보의 id값과 닉네임 값을 사용하기 위해 res.locals.user/userNickname에 저장
★ moongoose대신 sequelize를 사용 해 구현
- find를 findOne, findAll로 변경하고 대부분은 같은 코드로 구현이 되었음(model 작성 시, user와 post 관계가 1:N 관계로만 설정되도록 변경하면 끝!)
./model/users.js
this.hasMany(models.Posts, {
sourceKey: "userId",
foreignKey: "UserId",
});
./model/posts.js
this.belongsTo(models.Users, {
targetKey: "userId",
foreignKey: "UserId",
});
※ , develop하기 전에 try~catch를 함수로 만들어서 사용했었는데, 이 함수를 미들웨어로 작성해 리팩토링을 해볼 계획