[Node.js][MongoDB] MVC 모델의 Controller 작성하기
*Node.js 프로그래밍 입문(고경희)를 읽고 작성한 글입니다.
Design Architecture
코드 관리를 편리하게 하기 위해 기능이나 역할에 따라 여러 파일로 나눈 뒤 연결해 사용하는 개념
백엔드는 주로 MVC 패턴 이용
백엔드는 API 개발이라고도 볼 수 있는데, 이 API를 애플리케이션으로 만들려면 인터페이스(UI)가 필요하다.
{ UI: View, API: Controller, DB: Model }
모델과 뷰는 컨트롤러를 통해서만 정보 전달이 일어나므로 뷰와 모델은 완전히 분리된다.
- 브라우저가 POST를 통해 자료를 만들때도 컨트롤러를 거쳐 DB에 값을 저장하고, DB에서 값을 가져와 브라우저 화면에 출력할 때도 컨트롤러를 거쳐 모델에서 뷰로 정보가 이동한다.
영역 | 역할 | 설명 |
Model | DB와 연결해 데이터 처리 로직 | 애플리케이션 처리 대상 DB를 통해 자료 저장, 검색, 수정 함수가 모델에 해당 사용자에게 어떻게 보일지 생각하지 않고 처리 대상에 집중 |
View | 인터페이스 | 컨트롤러나 모델의 처리 결과를 시각적으로 표현 서버에서 가져온 동적 자료를 표시하므로 템플릿 형태로 저장 |
Controller | 모델과 뷰 수정 | 모델과 뷰 중간에 위치해 요청에 따라 모델이나 뷰 수정하는 역할 노드 라우트 코드가 컨트롤러에 해당 - 라우트 코드가 길지 않으면 함수로 분리하지 않는 방법도 자주 사용 |
라우트 코드에는 HTTP 요청을 받아 처리하는 함수가 get, post 등 함수의 콜백 형태로 포함되어 있다. 라우트 코드가 복잡해서 요청에 따라 콜백에 들어있는 함수가 많아지면 교통 경찰처럼 정보 요청과 그에 따른 작업 처리 함수를 정리한다. 이 역할 라우터 객체가 한다. 컨트롤러에서 라우터 객체를 분리하여 컨트롤러는 DB에 연결해 작업 처리하는 함수들만 남게 된다.
- 브라우저에서 모든 연락처 정보 요청
- 정보 요청은 라우터를 통해 컨트롤러의 해당하는 함수로 연결
- DB에 접근해야 하므로 컨트롤러에서 모델로 요청
- 모델은 컨트롤러에게 받은 정보로 DB 자료 조회
- DB에서 모델로 정보 송신
- 모델은 DB에서 받은 정보 컨트롤러로 전달
- 컨트롤러는 모델에서 받은 정보를 뷰로 전달
- 뷰에서 지정한 형식대로 최종 결과를 브라우저 화면에 출력
vue.js의 프로젝트 생성으로 생기는 기본 파일과 axios를 node의 express 프레임워크로 직접 서버 구현하는 과정이다.
route.js
// 기존 코드
router
.route('/')
.get((req, res) => {
res.status(200).send('Transactions Page');
})
// router 분리 후
const getAllTransactions = require("../controllers/transactionController")
router
.route('/')
.get(getAllTransactions)
controller.js
// CRUD 에 따른 처리 함수
// @desc Get all transactions 함수 설명
// @route Get /transactions 요청 방식과 URL
const getAllTransactions = async(req, res)=>{
try{res.status(200).send('Transactions Page')}
catch(err){ res.send(err.message);}
};
module.exports = getAllTransactions;
오류 체크를 위해 사용하던 try, catch는 미들웨어 express-async-handler를 이용해 코드를 간결하게 관리한다.
const asyncHandler = require("express-async-handler");
const getAllTransactions = asyncHandler(async(req, res)=>{
res.status(200).send('Transactions Page');
});
이제 컨트롤러에서 모델을 사용하려면 모델을 가져와서 변수에 할당해야 한다.
⤵️ 참고
MVC 모델에서 모델[MongoDB]과 컨트롤러 연결하기
*Node.js 프로그래밍 입문(고경희)를 읽고 작성한 글입니다. 몽고DB : 분산형 NoSQL DB로 JSON 형식을 이용해 문서에 자료 저장.Collection: 여러 개의 도큐먼트로 구성된 자료 저장 방식Document : 자료 저장
ahranah.tistory.com
Mongoose의 model을 모듈로 내보내고 컨트롤러 파일 변수로 할당해서 DB Document 자료 처리 함수를 사용한다.
// @create Document
Transaction.create({name: 'Kim', email: 'kim@abc.kr', id:'uuid4'})
// @find Document
Transaction.find({id:"3"})
// @findByID Check Document Validation
Transaction.findById('2324');
Transaction.findByIdAndUpdate(
id, {name, email}
);
Transaction.findByIdAndDelete(req.params.id);
// @update Find Document and Update content
Transaction.updateMany({name: "Kim"}, {email: "Park@abc.kr"})
// @delete Find Document and Delete first one or Many
Transaction.deleteOne({id: "uuid4"})
- find는 조건없이 사용하면 모든 자료를 가져온다.
거래 내역에서 거래명을 바꾼다고 해보자.
// @desc Update transactions
// @route PUT /transactions/:id
const updateTransaction = asyncHandler(async (req, res) => {
console.log('updateTransaction' + req.body);
const id = req.params.id;
const {name, email} = req.body;
// DB @find corresponding transaction
const transaction = await Transaction.findById(id);
if (!transaction){
res.status(404);
throw new Error("Transaction not found")
}
// DB @edit
transaction.name = name;
transaction.email = email;
// DB @save
transaction.save();
res.status(200).json(transaction);
});
근데 여기서 findByIdAndUpdate를 이용하면 함수가 간단해진다. 그럼 findById는 사용하지 않아도 되는거아닌가? 싶다.
findById는 도큐먼트 수정 전에 데이터를 볼 수 있으므로 유효성 검사 등에 이용할 수 있다.
const updatedTransaction = await Transaction.findByIdAndUpdate(
id,
{ name, email },
// 수정 결과 화면 출력을 위한 도큐먼트 반환
{ new: true }
);
res.status(200).send(updatedTransaction);
});