어제 작성한 reviews.repository.js를 프로젝트에서 팀원들끼리 정한 형식에 따라 변경하였다.
// src/repositories/reviews.repository.js
import { prisma } from '../utils/prisma/index.js';
class PostsRepository {
#orm;
constructor(orm) {
this.#orm = orm;
}
findAllReviews = async () => {
// ORM인 Prisma에서 review 모델의 findMany 메서드를 사용해 데이터를 요청합니다.
const reviews = await this.#orm.review.findMany();
return reviews;
};
findReviewById = async (reviewId) => {
// ORM인 Prisma에서 review 모델의 findUnique 메서드를 사용해 데이터를 요청합니다.
const review = await this.#orm.review.findUnique({
where: { reviewId: +reviewId }, // 수정 필요
});
return review;
};
createReview = async (restaurantId, paymentId, userId, content, star) => {
// ORM인 Prisma에서 review 모델의 create 메서드를 사용해 데이터를 요청합니다.
const createdReview = await this.#orm.review.create({
data: {
restaurantId: +restaurantId,
paymentId: paymentId,
userId: userId,
content: content,
star: +star,
},
});
return createdReview;
};
updateReview = async (reviewId, content, star) => {
// ORM인 Prisma에서 review 모델의 update 메서드를 사용해 데이터를 수정합니다.
const updatedReview = await this.#orm.review.update({
where: {
reviewId: parseInt(reviewId, 10),
},
data: {
...(content && { content }),
...(star && { star }),
},
});
return updatedReview;
};
deleteReview = async (reviewId) => {
// ORM인 Prisma에서 review 모델의 delete 메서드를 사용해 데이터를 삭제합니다.
const deletedReview = await this.#orm.review.delete({
where: {
reviewId: parseInt(reviewId, 10),
},
});
return deletedReview;
};
}
export default new PostsRepository(prisma);
기존의 코드는 PostsRepository 클래스 내에서 prisma를 직접 사용하는 방식이었는데, 위 코드처럼 PostsRepository 클래스는 orm을 생성자에서 받아서 내부적으로 저장하도록 변경하였다.
#orm은 private 필드로, 클래스 외부에서는 접근할 수 없다.
이때 굳이 private 속성을 사용하는 이유에 대한 의문이 생겨 이에 대해 질문하고 검색을 통해 찾아보았다.
캡슐화 (Encapsulation) : private 속성은 클래스 외부에서 접근할 수 없음. 클래스의 내부 상태를 보호. 외부에서 직접 수정할 수 없게 만든다.
데이터 무결성 (Data Integrity) : 클래스의 내부 데이터가 외부에서 임의로 변경되는 것을 방지(클래스 내부에서면 데이터 수정 가능). 데이터의 일관성과 무결성을 유지
유지보수성 (Maintainability) : 클래스의 내부 구현을 변경하더라도, 외부 코드에 영향을 미치지 않는다(문제 최소화). 유지보수를 용이하게 함
크게 위 같은 이유가 있다.
추가로 대규모 프로젝트일수록 문제가 발생했을 때 클래스 내부만 확인하는, 즉 문제를 국소화한 영역에서 수정할 수 있다거나, 모듈화 되어 팀원들이 독립적으로 개발하고 클래스 이해에 혼란을 줄여준다는 장점도 있다.
API 작성 시 많은 유효성 검증을 동반하게 되는데, 현재처럼 리포지토리, 컨트롤러, 서비스 3 계층으로 구성할 때 각 계층마다 어떤 유효성 검증을 진행하는 것이 적절한지 질문하고 찾아보았다.
질문한 결과 주로 서비스 계층에서 많은 검증 부분을 가지고 있는 것이 일반적이고 컨트롤러 계층에서는 들어오고 나가는 값, 리포지토리계층에서는 db관련 검증이 진행되는 것 확인했다.
다만 명확하게 구분되어서 공식처럼 정해져 있는 부분은 아닌 듯했다. 그래서 검색과 답변을 통해 리뷰 crud에서 필요한 검증들을 나름대로 구분하여 적용하기로 했다.
1. 리포지토리 계층
데이터베이스와의 상호작용을 관리하는 계층
- 데이터 변조 검증
db에 저장되기 전 모든 입력값의 형식이 올바른지 확인
ex : 리뷰 저장 전 모든 데이터들의 형식이 설계한 테이블의 칼럼별 타입과 같은지 확인하는 경우
2. 서비스 계층
비즈니스 로직을 처리하며, 컨트롤러와 리포지토리 간 중재 역할.
주로 서비스 계층에서 많은 유효성 검증 수행
- 중복 방지
ex : 결제별 하나의 리뷰만 작성 가능하도록 하여 데이터의 무결성 유지
- 수정 관련 검증
ex : 리뷰 수정 시 변경된 내용이 있는지 확인
- 존재 검증
ex : 수정, 삭제 전 이미 존재하는 리뷰가 있는지 확인
3. 컨트롤러 계층
클라이언트로부터 받은 요청 데이터의 유효성이나 보내는 메시지, 상태코드, 데이터 등을 검증
- 필수 필드 검증
ex : API 실행에 필요한 필드들이 모두 전달되어 있는지 누락 검증
- 별점 유효성 검증
ex : star가 1-5 사이 값인지 검증
컨트롤러 계층: 필수 필드 및 별점 유효성 검증
서비스 계층: 중복 리뷰 방지, 리뷰 존재 여부 확인, 수정할 필드 검증, 별점 유효성 검증
저장소 계층: 데이터 변조 방지 (선택적)
먼저 기술한 대로 공식처럼 적용할 수는 없는 부분 같아 임의로 진행할 예정.
'TIL' 카테고리의 다른 글
내일배움캠프 11주차 금요일 TIL (0) | 2025.01.10 |
---|---|
내일배움캠프 11주차 목요일 TIL (0) | 2025.01.09 |
내일배움캠프 11주차 화요일 TIL (0) | 2025.01.07 |
내일배움캠프 10주차 목요일 TIL (0) | 2025.01.02 |
내일배움캠프 9주차 목요일 TIL (0) | 2024.12.26 |