들어가기 전에..
지난 시간까지는 개발환경 세팅하는 방법과 회원가입, 로그인, 게시글CRUD 구현까지 알아보았다.
이번 3탄에서는 댓글기능(Cmt), 좋아요(like)기능을 넣어보도록 하겠다.
[아직까지 like기능은 미구현입니다..ㅠ 이번 주말 안에 업로드 예정입니다.]
https://jh-healing-place.tistory.com/105
[14] 회원가입, 로그인, 게시판CRUD 구현해보자! (Node.js x mySQL x sequelize) 1탄
1. 들어가기 전에 개발자라고 하면 모두들 CRUD는 기본이라고한다. 하지만 이 CRUD를 구현한다는게 가장 어렵고 이를 자유자재로 구현하게 되면 그때서야 비로소 초급 개발자의 문턱에 들어갔다고
jh-healing-place.tistory.com
https://jh-healing-place.tistory.com/117
[15] 회원가입, 로그인, 게시판CRUD 구현해보자! (Node.js x mySQL x sequelize) 2탄
1. 들어가기 전에.. 여기서는 본격적으로 로그인, 로그아웃 기능을 위해 user라는 DB를 만들고 게시글과 댓글 기능을 위한 post와 cmt라는 DB를 만들어보도록 하겠다. ( 환경세팅 방법은 아래 1탄에 있
jh-healing-place.tistory.com
1. 댓글기능 (Cmt), 좋아요 기능 구현
# 1. migration 생성 및 수정 ( 댓글, contentId라는 값을 가지고 있는 like table )
- npx sequelize model:generate --name Cmts --attributes userId:Integer,postId:Integer,cmtId:Integer,content:String
- npx sequelize model:generate --name like --attributes userId:Integer,contentId:Integer
# 2. DB 생성 및 Migrations에 정의된 테이블 MySQL에 생성
npx sequelize db:create
npx sequelize db:migrate
// cmt migration
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Cmts', {
cmtId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
postId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: "Posts",
key: "postId",
},
onDelete: "CASCADE",
},
userId: {
allowNull: false,
type: Sequelize.INTEGER,
references: {
model: "Users",
key: "userId",
},
onDelete: "CASCADE",
},
content: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Cmts');
}
};
// like migrations
# 3. migration 파일 수정 및 model 폴더 내부 파일 세팅
// cmt models
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Cmts extends Model {
static associate(models) {
// Users와 Cmts는 일대다 관계
this.belongsTo(models.Users, {
targetKey: "userId",
foreignKey: "userId",
});
// Posts와 Cmts는 일대다 관계
this.belongsTo(models.Posts, {
sourceKey: "cmtId",
foreignKey: "postId",
});
}
}
Cmts.init({
cmtId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
postId: {
allowNull: false,
type: DataTypes.INTEGER,
},
userId: {
allowNull: false,
type: DataTypes.INTEGER,
},
content: {
allowNull: false,
type: DataTypes.STRING,
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE,
},
}, {
sequelize,
modelName: 'Cmts',
});
return Cmts;
};
// like models
2. Route 설정
// cmtsRoute
const express = require('express');
const router = express.Router();
const authMiddleware = require('../middlewares/authMiddleware');
const { Cmts } = require('../models');
const { Op } = require('sequelize');
// 댓글 목록 조회 API (GET)
router.get('/posts/:postId/cmts', async (req, res) => {
const cmts = await Cmts.findAll({
attributes: ['cmtId', 'postId', 'content', 'createdAt', 'updatedAt'],
order: [['createdAt', 'DESC']]
});
return res.status(200).json({ data: cmts });
});
// 댓글 작성 API (POST)
router.post('/posts/:postId/cmts', authMiddleware, async (req, res) => {
const { userId } = res.locals.user;
const { postId } = req.params;
const { content } = req.body;
const cmt = await Cmts.create({
userId: userId,
postId: postId,
content: content
});
return res.status(201).json({ data: cmt });
});
// 댓글 수정 API (PUT)
router.put('/posts/cmts/:cmtId', authMiddleware, async (req, res) => {
const { cmtId } = req.params;
const { userId } = res.locals.user;
const { content } = req.body;
const cmt = await Cmts.findOne({ where: { cmtId } });
if (!cmt) {
return res.status(404).json({ message: '해당 댓글이 존재하지 않습니다.' });
} else if (cmt.userId !== userId) {
// 404 => 403
return res.status(403).json({ message: '권한이 없습니다.' });
}
await Cmts.update(
{ content },
{
where: {
[Op.and]: [{ cmtId }, { userId }]
}
}
);
return res.status(200).json({ data: '댓글이 수정되었습니다.' });
});
// 댓글 삭제 API (DELETE)
router.delete('/posts/cmts/:cmtId', authMiddleware, async (req, res) => {
const { cmtId } = req.params;
const { userId } = res.locals.user;
const { content } = res.req.body;
const cmt = await Cmts.findOne({ where: { cmtId } });
if (!cmt) {
return res.status(404).json({ message: '해당 댓글이 존재하지 않습니다.' });
} else if (cmt.userId !== userId) {
// 404 => 403
return res.status(403).json({ message: '권한이 없습니다.' });
} else if (cmt.content !== content) {
return res.status(401).json({ message: '내용이 일치하지 않습니다.' });
}
await Cmts.destroy({
where: {
[Op.and]: [{ cmtId }, { userId }]
}
});
return res.status(200).json({ data: '댓글이 삭제되었습니다.' });
});
module.exports = router;
// likeRoute
3. app.js 수정
const cors = require('cors');
const express = require('express');
const app = express();
const port = 3000;
const path = require('path');
// cookie parser
const cookieParser = require('cookie-parser');
const usersRouter = require('./routes/usersRoute.js');
const postsRouter = require('./routes/postsRoute.js');
const cmtsRouter = require('./routes/cmtsRoute.js');
// Middleware ==================================================
app.use(express.json()); // req.body parser
app.use(cookieParser()); // cookie parser
app.use(cors()); // front-back connect
// localhost:3000/api/
app.use('/api', [usersRouter]);
app.use('/api', [postsRouter]);
app.use('/api', [cmtsRouter]);
// Middleware ==================================================
// HTML, CSS
app.use(express.static(path.join(__dirname, 'assets')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'assets', 'index.html'));
});
// server start!!
app.listen(port, () => {
console.log(port, '서버가 켜졌습니다.');
});
3탄에 걸쳐서 회원가입, 로그인, 게시글CRUD, 댓글CRUD, 좋아요까지 끝이 났다.
마지막 4탄에서는 이를 바탕으로 레이어드 아키텍쳐 패턴을 적용해보려한다.
3탄 끝~~

'프로그래밍 > Node.js' 카테고리의 다른 글
[20] todoList 프로젝트 - 회고 ( node.js 6조 ) (1) | 2023.08.14 |
---|---|
[19] todoList 프로젝트 ( node.js 6조 ) (0) | 2023.08.07 |
[15] 회원가입, 로그인, 게시판CRUD 구현해보자! (Node.js x mySQL x sequelize) 2탄 (0) | 2023.07.25 |
[18] Node.js Qwerty 프로젝트 회고 (0) | 2023.07.24 |
[17] Node.js Qwerty 프로젝트 (node.js 4조) (0) | 2023.07.17 |