공동 구매 마켓 프로젝트에서 찜하기 기능을 구현했다. 처음에는 어떻게 설계해야할지 고민이 많았는데 그 내용을 정리해보려고한다.
1. 구현해야할 API
- 물품 찜하기
- 내가 찜한 물품 조회
2. 테이블 설계
CREATE TABLE Wishlists (
wishlist_id INT PRIMARY KEY AUTO_INCREMENT, -- 위시 리스트 ID (Primary Key)
user_id INT NOT NULL, -- 사용자 ID (Foreign Key)
product_key INT NOT NULL, -- 찜한 상품 ID (Foreign Key)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,-- 생성일
FOREIGN KEY (user_id) REFERENCES User(user_id) ON DELETE CASCADE,
FOREIGN KEY (product_key) REFERENCES Product(product_key) ON DELETE CASCADE,
UNIQUE (user_id, product_key)
);
설계의 주요 포인트
- Foreign Key:
- user_id와 product_key는 각각 User와 Product 테이블과 연결되어 있기 때문에 데이터 무결성을 유지하도록했다.
- 중복 방지:
- user_id와 product_key의 조합을 UNIQUE 제약 조건으로 설정해 동일한 물품이 중복 저장되지 않도록 했다.
- 연쇄 삭제:
- ON DELETE CASCADE로 설정해 사용자가 삭제되거나 물품이 삭제되면 관련된 찜하기 데이터도 자동으로 삭제되도록 구현했다.
3. API 구현
1) 물품 찜하기
찜하기는 product_key와 세션에 담긴 user_id를 통해 구현했다.
먼저 user_id와 product_key를 통해 Wishlists 테이블에서 데이터를 조회했다. 이때 데이터가 존재한다면 그 데이터를 삭제, 존재하지 않는다면 데이터를 삽입하도록 했다. 그래야 데이터의 양이 불필요하게 많아지는 것을 방지할 수 있다고 생각했기 때문이다.
exports.postWishlists = async (req, res) => {
try {
const userId = req.session.user.user_pk; // 세션에서 user_id 가져오기
const productKey = req.params.product_key; // URL에서 product_key 가져오기
// db에서 상태 확인
const wishlist = await Wishlists.findOne({
where: { user_id: userId, product_key: productKey },
});
if (wishlist) {
// 위시 리스트에서 삭제
await wishlist.destroy();
return res.status(200).send({
isSuccess: true,
message: '위시 리스트에서 삭제되었습니다.',
});
} else {
await Wishlists.create({
user_id: userId,
product_key: productKey,
});
return res.status(200).send({
isSuccess: true,
message: '위시 리스트에 추가되었습니다.',
});
}
} catch (error) {
console.log('err', error);
return res
.status(500)
.send({ isSuccess: false, message: '서버 오류가 발생했습니다.' });
}
};
2) 내가 찜한 물품 조회
내가 찜한 물품은 user_id를 통해 가져왔다. Wishlists 테이블에서 user_id의 product_key의 정보를 모두 가져오고, 이를 이용해 Product 테이블에서 찜한 물품의 정보들을 가져왔다.
exports.getWishlists = async (req, res) => {
try {
// 세션에서 사용자 ID 가져오기
const userId = req.session.user ? req.session.user.user_pk : null;
if (!userId) {
// 로그인하지 않은 경우 로그인 페이지로 리다이렉트
return res.redirect('/auth/login');
}
// 찜한 상품 가져오기
const wishlists = await Wishlists.findAll({
where: { user_id: userId },
attributes: ['product_key'],
});
if (wishlists.length === 0) {
return res.render('wishlist', {
isSuccess: true,
message: '찜한 상품이 없습니다.',
products: [],
});
}
const productKeys = wishlists.map((wishlist) => wishlist.product_key);
const products = await Product.findAll({
where: { product_key: productKeys },
});
res.render('wishlist', {
isSuccess: true,
message: '찜한 상품 목록입니다.',
products,
});
} catch (error) {
console.error('찜한 상품 렌더링 오류:', error);
res.status(500).send('서버 오류');
}
};

이렇게 찜하기 관련 API를 구현 완료했다.
'🙋♀️ Server' 카테고리의 다른 글
| [Server] Spring Security가 뭐지? (2) | 2025.01.29 |
|---|---|
| [Server] Spring 패키지 구조, 각각의 기능 (0) | 2025.01.21 |
| [Server] sequelize를 이용한 중첩 조인 (0) | 2024.12.28 |
| [Server] Database 설계 & SQL 1452 문제 해결 (2) | 2024.12.17 |
| [Web] MySQL + Node.js로 MVC 패턴 적용 (2) | 2024.12.03 |