[Database] MVC, im-sprint-cmarket-database (router, controller)

윤태영 | Taeyoung Yoon·2022년 5월 17일
0

TIL (Today I Learned)

목록 보기
39/53
post-thumbnail

MVC 패턴

MVC란 Model-View-Controller의 약자로 어플리케이션을 세 가지 역할로 구분한 개발 방법론이다.
아래의 그림처럼 사용자가 Controller를 조작하면 Controller는 Model을 통해 데이터를 가져오고 그 데이터를 바탕으로 View를 통해 시각적 표현을 제어하여 사용자에게 전달하게 된다.

1. 사용자가 웹사이트에 접속
2. Controller는 사용자가 요청한 웹페이지를 서비스하기 위해서 모델 을 호출
3. Model은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후 그 결과를 Return
4. Controller는 Model이 리턴한 결과를 View에 반영
5. 데이터가 반영된 View는 사용자에게 보여짐 

view를 서버가 맡게되면 server side rendering (SSR) 이고
클라이언트가 맡게되면 client side rendering (CSR) 이다.

im-sprint-cmarket-database

이번 스프린트에서는 쇼핑몰 애플리케이션 Cmarket의 데이터베이스를 구축한다.
모든 요청은 반드시 데이터베이스를 이용해야 한다.

mySQL 접속 후 cmarket 데이터베이스 생성
CREATE DATABASE cmarket;


미리 구성되어있는 Cmarket 스키마를 기반으로 데이터베이스 테이블 생성
스프린트 레포지토리 진입 후
mysql -u root -p < server/schema.sql -Dcmarket 스키마 복사

schema.sql 파일은 관계형 데이터베이스의 기초 뼈대 역할을 한다.
필요한 명령을 정리한 파일이다.

mysql -u root -p < server/seed.sql -Dcmarket 테이블에 데이터 저장

seed.sql 파일은 생성한 데이터베이스 테이블에 준비된 데이터를 갖고 있다.
데이터베이스의 스키마의 구성과 다르면 데이터가 저장되지 않는다.

잘못된 SQL을 작성하여 잘못된 데이터베이스 및 테이블이 생성된 경우
DROP DATABASE IF EXISTS [다시 생성하려는 데이터베이스] CREATE DATABASE [다시 생성하려는 데이터베이스] 를 입력하면 잘못 생성된 데이터베이스를 삭제하고 작성된 SQL 명령어에 따라 데이터 베이스를 다시 생성한다.


서버

npm install 명령어로 서버폴더에 필요한 모듈을 설치한다
pakage.json에 npm 모듈 mysql이 기록되어있다.

보안상 이유로 mySQL의 비밀번호를 사용하기 위해 비밀번호를 환경변수 .env 에 분리해 놓는다.


app.js 파일은 express의 설정을 담당하는 파일이다.
express 는 Node.js 웹 서버의 진입점이자 자바스크립트의 서버 프레임워크 중 하나로
파일 구조를 파악하고, app.js 에서 라우팅 연결이 어떻게 시작되는지 확인한다.

/app.js

const express = require('express');
const indexRouter = require('./routes');  
const cors = require('cors');
const morgan = require('morgan');
const app = express();
const port = 4000;

app.use(
  morgan('      :method :url :status :res[content-length] - :response-time ms')
);
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use('/', indexRouter);

module.exports = app.listen(port, () => {
  console.log(`      🚀 Server is starting on ${port}`);
});

모든 요청은 indexRouter 를 거친다.


Router

/db/routes/index.js

const express = require('express');
const router = express.Router();
const itemsRouter = require('./items');
const usersRouter = require('./users'); 

router.use('/items', itemsRouter);
router.use('/users', usersRouter);

module.exports = router;

모든 라우터의 진입점으로 여기서 endpoint에 따라 다시 분기된다.
users 앤드포인트로 들어온 요청은 usersRouter를 통하게 한다.


/db/routes/items.js

const router = require('express').Router();
const controller = require('./../controllers');

router.get('/', controller.items.get);

module.exports = router;

GET /items Router와 Controller를 연결한다.


/db/routes/users.js

const router = require('express').Router();
const controller = require('./../controllers');

router.get('/:userId/orders', controller.orders.get);
router.post('/:userId/orders', controller.orders.post);
 
module.exports = router;

GET /users/1/orders 방식으로 요청이 들어온다.
userId는 파라미터이므로 콜론을 붙힌다.


Controller

다음 세 endpoint에 대한 각기 다른 구현이 필요하다

  • GET /items
  • GET /users/:userId/orders
  • POST /users/:userId/orders

/controllers/index.js

const models = require('../models');

module.exports = {
  items: {
    get: (req, res) => {
      models.items.get((error, result) => {
        if (error) {
          res.status(500).send('Internal Server Error');
        } else {
          res.status(200).json(result);
        }
      });
    },
  },
  orders: {
    get: (req, res) => {
      const userId = req.params.userId;
      models.orders.get(userId, (error, result) => {
        if(error){
          res.sendStatus(500); // 서버 내부 에러 상태코드 500
        } else {
          res.json(result); // 조회를 했으므로 결과를 json형식으로 보내준다
        }
      });
    },
    post: (req, res) => {
      const userId = req.params.userId; 
      //파라미터 userID변수에 접근
      const { orders, totalPrice } = req.body;
      //요청바디 구조분해할당
      if(!orders || !totalPrice){ //orders 나 totalPrice가 없을 경우 상태코드400을 보낸다. 
        res.status(400).send(); //클라이언트 비정상적인 요청 에러 상태코드 400
      } else {
        models.orders.post(userId, orders, totalPrice, (error, result) => {
          //서버가 데이터베이스에서 자료를 찾고 상태를 보내줘야 되므로(비동기) 콜백함수를 사용한다.
          if(error){
            res.sendStatus(500); // 서버 내부 에러 상태코드 500
          } else {
            res.sendStatus(201); // 클라이언트 PUT 요청이 성공한 상태코드 201
          }
        });
      }
    },
  },
};

다음과정

0개의 댓글