CommentsService 구현CommentsService 개요CommentsService는 NestJS와 TypeORM을 활용하여 댓글을 생성, 조회, 수정, 삭제하는 기능을 제공하는 서비스입니다.
createComment)async createComment(cardId: number, userId: number, content: string)
cardId, userId, content를 입력받아 새로운 댓글을 생성 this.commentRepository.create()를 사용해 새로운 댓글 객체를 만들고 save()를 통해 DB에 저장 getCommentByCardId)async getCommentByCardId(cardId: number)
findBy()를 사용하여 특정 카드에 속한 모든 댓글을 조회 getCommentById)async getCommentById(id: number)
findOneBy()를 이용해 특정 ID의 댓글을 조회 NotFoundException 예외 발생 updateComment)async updateComment(id: number, userId: number, content: string)
verifyComment()를 호출하여 댓글이 존재하는지, 사용자가 작성자인지 검증 update()를 이용해 댓글 내용 수정 findOneBy()로 다시 조회하여 반환 deleteComment)async deleteComment(id: number, userId: number)
verifyComment()를 호출하여 삭제 권한을 확인 delete()를 사용하여 DB에서 댓글 삭제 후 메시지 반환 verifyComment)private async verifyComment(id: number, userId: number)
userId가 일치하지 않으면 NotFoundException 예외 발생 1️⃣ NestJS의 Injectable과 InjectRepository
Injectable()을 사용해 서비스 클래스를 주입 가능하게 만듦 InjectRepository(Comment)를 활용해 commentRepository를 TypeORM과 연결 2️⃣ TypeORM의 CRUD 메서드 활용
create(), save(), findBy(), findOneBy(), update(), delete() 등의 ORM 메서드를 활용하여 DB 조작 3️⃣ Lodash를 활용한 데이터 검증 (_.isNil())
_.isNil(comment)를 사용해 null 또는 undefined 여부를 확인하여 예외 처리 getCommentByCardId()에서 댓글이 없을 경우 예외를 던지는 로직 추가 가능 updateComment()와 deleteComment()에서 verifyComment()를 호출하므로, 중복되는 조회 쿼리를 줄일 방법 고려 가능 NestJS + TypeORM을 활용한 댓글 서비스 구현을 통해 CRUD 로직을 정리할 수 있었다!
comments.service.ts
import { Repository } from 'typeorm';
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import _ from 'lodash';
import { Comment } from './entities/comment.entity';
@Injectable()
export class CommentsService {
constructor(
@InjectRepository(Comment)
private commentRepository: Repository<Comment>,
) {}
async createComment(cardId: number, userId: number, content: string) {
const newComment = this.commentRepository.create({
cardId,
userId,
content,
});
return await this.commentRepository.save(newComment);
}
async getCommentByCardId(cardId: number) {
return await this.commentRepository.findBy({
cardId: cardId,
});
}
async getCommentById(id: number) {
const comment = await this.commentRepository.findOneBy({ id });
if (_.isNil(comment)) {
throw new NotFoundException('댓글을 찾을 수 없습니다.');
}
return comment;
}
async updateComment(id: number, userId: number, content: string) {
await this.verifyComment(id, userId);
await this.commentRepository.update({ id }, { content });
return await this.commentRepository.findOneBy({ id });
}
async deleteComment(id: number, userId: number) {
await this.verifyComment(id, userId);
await this.commentRepository.delete({ id });
return { id, message: '삭제되었습니다.' };
}
private async verifyComment(id: number, userId: number) {
const comment = await this.commentRepository.findOneBy({
id,
});
if (_.isNil(comment) || comment.userId !== userId) {
throw new NotFoundException(
'댓글을 찾을 수 없거나 수정/삭제할 권한이 없습니다.',
);
}
}
}