KB_ITs_Your_Life_6th/Node.js

[Node.js][MongoDB] MVC 모델의 Controller 작성하기

아란정 2025. 4. 21. 12:50
728x90
반응형

*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에 연결해 작업 처리하는 함수들만 남게 된다.

  1. 브라우저에서 모든 연락처 정보 요청
  2. 정보 요청은 라우터를 통해 컨트롤러의 해당하는 함수로 연결
  3. DB에 접근해야 하므로 컨트롤러에서 모델로 요청
  4. 모델은 컨트롤러에게 받은 정보로 DB 자료 조회
  5. DB에서 모델로 정보 송신
  6. 모델은 DB에서 받은 정보 컨트롤러로 전달
  7. 컨트롤러는 모델에서 받은 정보를 뷰로 전달
  8. 뷰에서 지정한 형식대로 최종 결과를 브라우저 화면에 출력

 

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);
});

 

728x90