본 내용은 내일배움캠프에서 활동한 내용을 기록한 글입니다.
상품 게시글 작성 API에서 사진URL를 picture 테이블에 넣어야 함
그래서 trade 테이블 스키마에서 img 컬럼이 필요 없을 것 같음
trade 스키마 수정
입력 받은 이미지 URL 배열을 순서대로 picture 테이블에 삽입
찾아보니 트랜젝션을 이용해서 상품 등록과 상품 사진 URL 등록을 동시에 진행해야 함
// 상품 게시글 작성 API
tradeRouter.post('/create', accessTokenValidator, createTradeValidator, async (req, res, next) => {
try {
// 유효성 검사 거치고 req.body 가져옴
const { title, content, price, region, img } = req.body;
console.log(img);
// 상품 생성 + 이미지 등록 트랜젝션으로 처리
const trade = await prisma.$transaction(async (tx) => {
// 상품 생성
const newTrade = await tx.trade.create({
data: { title, content, price, region, userId: req.user.id },
});
// 상품 사진 등록
// 이미지가 여러 장인 경우 Promise.All로 비동기적으로 실행
const tradeImg = await Promise.all(
img.map(async (url) => {
return await tx.tradePicture.create({ data: { tradeId: newTrade.id, imgUrl: url } });
})
);
return [newTrade, tradeImg];
});
return res.status(HTTP_STATUS.CREATED).json({
status: HTTP_STATUS.CREATED,
message: MESSAGES.TRADE.CREATE.SUCCEED,
data: { trade },
});
} catch (err) {
next(err);
}
});
일종의 뉴스피드 구현
데이터베이스에 등록된 모든 상품을 조회
기본적으로 최신 순으로 정렬, 정렬 옵션으로 좋아요 순으로도 조회
시간 순 정렬 또는 좋아요 순으로 정렬해서 조회
상품 게시글 목록 조회에서 상품 사진도 같이 반환하도록 수정 필요
// 상품 게시글 목록 조회 API (뉴스피드)
tradeRouter.get('/', async (req, res) => {
// 정렬 조건 쿼리 가져오기
let sortDate = req.query.sort.toLowerCase();
let sortLike = req.query.like?.toLowerCase();
// 시간 순 정렬 기본 값 설정
if (sortDate !== sort.desc && sortDate !== sort.asc) {
sortDate = sort.desc;
}
// 좋아요 순 정렬 기본 값 설정 (상세한 내용은 회의가 필요)
if (sortLike !== sort.desc && sortLike !== sort.asc) {
sortLike = sort.desc;
}
// trade 테이블의 데이터 모두를 조회
const trades = await prisma.trade.findMany({
orderBy: [/*{ like: sortLike },*/ { createdAt: sortDate }],
omit: { content: true },
});
return res
.status(HTTP_STATUS.OK)
.json({ status: HTTP_STATUS.OK, message: MESSAGES.TRADE.READ.SUCCEED, data: { trades } });
});
상품 상세 조회는 아무나 사용 가능
상품 목록과는 다르게 content 내용이 출력됨
상품 게시글 상세 조회에서 상품 사진도 같이 반환하도록 수정 필요
// 상품 게시글 상세 조회 API
tradeRouter.get('/:tradeId', async (req, res) => {
// 상품 ID 가져오기
const id = req.params.tradeId;
// 상품 조회하기
const trade = await prisma.trade.findFirst({ where: { id: +id } });
// 데이터베이스 상 해당 상품 ID에 대한 정보가 없는 경우
if (!trade) {
return res
.status(HTTP_STATUS.NOT_FOUND)
.json({ status: HTTP_STATUS.NOT_FOUND, message: MESSAGES.TRADE.READ.NOT_FOUND });
}
return res
.status(HTTP_STATUS.OK)
.json({ status: HTTP_STATUS.OK, message: MESSAGES.TRADE.READ.SUCCEED, data: { trade } });
});
수정할 항목들을 req.body로 입력 받음
반드시 모두 입력할 필요 없음
작성한 내용만 수정에 반영
상품 게시글 작성과 마찬가지로 트랜젝션을 통해 게시글 등록, 사진 등록을 같은 트랜젝션에서 동작 시킴
// 상품 게시글 수정 API
tradeRouter.patch(
'/:tradeId/edit',
accessTokenValidator,
updateTradeValidator,
async (req, res, next) => {
try {
// 상품 ID 가져오기
const id = req.params.tradeId;
// 상품 조회하기
const trade = await prisma.trade.findFirst({ where: { id: +id } });
// 데이터베이스 상 해당 상품 ID에 대한 정보가 없는 경우
if (!trade) {
return res
.status(HTTP_STATUS.NOT_FOUND)
.json({ status: HTTP_STATUS.NOT_FOUND, message: MESSAGES.TRADE.READ.NOT_FOUND });
}
// 수정할 내용 입력 받음
const { title, content, price, region, img } = req.body;
// 게시글 수정 + 이미지 삭제 및 추가 트랜젝션으로 처리
const changedTrade = await prisma.$transaction(async (tx) => {
// 상품 수정
const tradeTemp = await tx.trade.update({
where: { id: trade.id },
data: {
...(title && { title }),
...(content && { content }),
...(price && { price }),
...(region && { region }),
},
});
// 상품 이미지 수정 (정확히는 삭제 후 등록)
// 이미지 개수가 다를 수도 있고 어떤 이미지가 어떤 이미지로 수정되는지 알 방법이 없음
await tx.tradePicture.deleteMany({ where: { tradeId: trade.id } });
const tradeImg = await Promise.all(
img.map(async (url) => {
return await tx.tradePicture.create({ data: { tradeId: trade.id, imgUrl: url } });
})
);
return [tradeTemp, tradeImg];
});
return res.status(HTTP_STATUS.CREATED).json({
status: HTTP_STATUS.CREATED,
message: MESSAGES.TRADE.UPDATE.SUCCESS,
data: { changedTrade },
});
} catch (err) {
next(err);
}
}
);
상품 게시글 목록 조회, 상세 조회 수정하기
상품 게시글 삭제 API 구현하기
삭품 게시글 좋아요 기능 구현하기
약간 뒤늦게 구현에 들어감
그래서 오늘은 게시글 생성, 게시글 목록 조회, 게시글 상세 조회, 게시글 수정까지만 구현함
사실 피곤한 상태에서 구현해서 내일 많은 테스트가 필요해 보임
상품 게시글을 등록하면 상품의 정보는 trade라는 테이블에 저장되고 상품 사진 URL은 trade_picture라는 테이블에 저장되어야 함
처음에는 따로따로 trade 테이블에 create 동작을 하고 trade_picture 테이블에 create 하는 동작을 하도록 함
그러니 trade_picture에서 에러가 발생하면 게시글은 등록되고 사진은 등록지되 않는 현상이 발생함
그래서 prisma의 트랜젝션 문법을 통해 동시에 처리함
// 상품 게시글 작성 API
tradeRouter.post('/create', accessTokenValidator, createTradeValidator, async (req, res, next) => {
try {
// 유효성 검사 거치고 req.body 가져옴
const { title, content, price, region, img } = req.body;
console.log(img);
// 상품 생성 + 이미지 등록 트랜젝션으로 처리
const trade = await prisma.$transaction(async (tx) => {
// 상품 생성
const newTrade = await tx.trade.create({
data: { title, content, price, region, userId: req.user.id },
});
// 상품 사진 등록
// 이미지가 여러 장인 경우 Promise.All로 비동기적으로 실행
const tradeImg = await Promise.all(
img.map(async (url) => {
return await tx.tradePicture.create({ data: { tradeId: newTrade.id, imgUrl: url } });
})
);
return [newTrade, tradeImg];
});
return res.status(HTTP_STATUS.CREATED).json({
status: HTTP_STATUS.CREATED,
message: MESSAGES.TRADE.CREATE.SUCCEED,
data: { trade },
});
} catch (err) {
next(err);
}
});