Node-10 라우터 분리(22/12/21)

nazzzo·2022년 12월 20일
0

라우터 분리

/root
|-- [-]models
|-- middlewares
|-- controller
|-- [-]service
|-- routes
|-- public
|-- views
|-- server.js


1. 라우터를 분리해야하는 이유

  • 프로젝트의 규모가 커지고 복잡해질수록 라우트들은 수많은 줄로 이어질 수 있고
    코드의 구조와 흐름을 한눈에 파악하기가 어려워집니다

  • 라우터를 분리하는 것은 코드의 구조를 깔끔하게 정리하기 위해서이자,
    유지보수가 편리하도록 하기 위함입니다

  • 협업과정에서도 멤버 각각이 다른 모듈로 작업하게 되기 때문에
    코드의 충돌 우려가 적어집니다

라우터를 분리하는 이유를 한줄요약하자면 '코드의 관리'를 위해서입니다



2. 라우터 분리 구조


가장 일반적인 방법은 라우터를 관리할 routes 디렉토리와
각 라우터의 콜백함수를 관리할 controller 디렉토리로 나누는 것입니다
필요에 따라 미들웨어를 따로 관리하기 위한 middleware 디렉토리를 추가하기도 합니다


아래에 간단한 예를 들어보겠습니다

요청 URL이 / 일 경우, "Hello World!" 를 응답으로 보내는
라우터와 컨트롤러 코드는 다음과 같습니다


서버(Server)
서버는 클라이언트의 요청을 받아들이는 입구 역할을 합니다

[server.js]

const router = require("./routes");
app.use(router);

라우터(Router)
서버에 들어온 요청을 어떤 컨트롤러에게 전달할지 결정하는 역할을 합니다

[router.js]

router.get('/', hello)

module.exports = router

컨트롤러(Controller)
컨트롤러는 요청을 처리한 결과를 응답으로 보내는 역할을 합니다

[controller.js]

//module.exports 생략문법
exports.hello = (req, res) => {
  res.send('Hello World!');
};

끝으로 미들웨어(Middleware)는 요청과 응답 사이에서 작동하는 함수입니다
요청을 처리하기 전에 요청에서 정보를 추출하거나,
응답을 생성한 후에 응답에 추가 정보를 삽입하는 등
요청과 응답 사이에서 어떤 추가적인 작업이 필요할 때의 역할을 담당합니다

아래와 같이 요청의 바디영역을 파싱하는 코드 역시 하나의 미들웨어입니다

app.use(express.urlencoded({extended: true}))

3. 라우터 분리하기


↓ 이제 이 난잡한 server.js 파일을 해체할 시간이 왔습니다

const express = require("express");
const nunjucks = require("nunjucks");
const app = express();
const PORT = process.env.SERVER_PORT || 3000;
let boardList = [];



const writeHandler = (req, res) => {
  const boardItem = req.body;
  boardList.push(boardItem);

  const getTimeNow = (date) => {
    let mm = date.getMonth() + 1; // 0 ~ 11
    mm = (mm > 9 ? "" : "0") + mm; // 01 02...09 10 11
    let dd = date.getDate(); // 1 ~ 31
    dd = (dd > 9 ? "" : "0") + dd;
    let yy = date.getFullYear();

    let hr = date.getHours()
    let min = date.getMinutes()
    let sec = date.getSeconds()
    return [yy, mm, dd].join("-")+"."+[hr, min, sec].join(".")
  };

  boardItem.date = getTimeNow(new Date());
  boardItem.hit = -1;
  boardItem.idx = boardList.length - 1;

  res.redirect(`/view?index=${boardItem.idx}`);
};

const modifyHandler = (req, res) => {
  const index = req.query.index;
  const boardItem = boardList[index];
  boardItem.subject = req.body.subject;
  boardItem.writer = req.body.writer;
  boardItem.content = req.body.content;
  
  // 객체 속성을 한꺼번에 선택하는 신문법
  // const {index, ...rest} = req.body
  // boardList[index] = rest

  res.redirect("/view?index=" + index);
};

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));

app.get("/", (req, res) => {
  const name = req.query.name;
  res.render("index.html", { name });
});

app.post("/list", (req, res) => {
  res.redirect("/list");
});

app.get("/list", (req, res) => {
  //검색 기능 구현
  const searchType  = req.query.searchType || 'writer';
  const search  = req.query.search
  const result = req.query.searchType === undefined 
  ? boardList
  : boardList.filter(obj => obj[searchType].includes(search));

  const reversedList = [...result].reverse();
  res.render("list.html", { boardList: reversedList });
  // nunjucks 내장 기능으로 화면 그리기
  // {% for item in Arr %}
  // {{ loop.index0 }}: {{ item }}
  // {% endfor %}
});

app.get("/write", (req, res) => {
  res.render("write.html");
});

app.post("/write", writeHandler);

app.get("/view", (req, res) => {
  const index = req.query.index;
  if (index < 0 || index >= boardList.length) {
    // 에러 방지용 빈 페이지 띄우기
    return res.render("view.html", { boardItem: {} });
  }
  const boardItem = boardList[index];
  boardItem.hit += 1;
  res.render("view.html", { boardItem, boardList });
});

app.post("/modify", modifyHandler);

app.get("/modify", (req, res) => {
  const index = req.query.index;
  const boardItem = boardList[index];

  res.render("modify.html", { boardItem, index });
});

app.post("/delete", (req, res) => {
  const index = req.body.index;
  boardList.splice(index, 1);
  res.redirect("/list");
});

app.listen(PORT, () => {
  console.log("server start");
});



1) route 디렉토리

[index.js]
index파일은 라우터끼리도 분기를 나눠야 할 경우가 생겼을 때
그 분기점을 결정할 최상위 라우터 역할을 합니다

const express = require('express')
const router = express.Router()
const board = require('./board.routes')
const gallery = require('./gallery.routes')


router.use("/board",board)
router.use("/gallery",gallery)

module.exports = router

[board.router.js]

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

router.get('/', controller.getIndex)
router.get('/list', controller.getList)
router.post('/list', controller.postList)
router.get('/write', controller.getWrite)
router.post('/write', controller.postWrite)
router.get('/view', controller.getView)
router.get('/modify', controller.getModify)
router.post('/modify', controller.postModify)
router.post('/delete', controller.postDelete)

module.exports = router

2) controller 디렉토리

[board.controller.js]

const boardList = []

exports.getIndex = (req, res)=>{
    const name = req.query.name;
    res.render("index.html", { name });
}

exports.getList = (req, res) => {
    const searchType  = req.query.searchType || 'writer';
    const search  = req.query.search
    const result = req.query.searchType === undefined 
    ? boardList
    : boardList.filter(obj => obj[searchType].includes(search));

    const reversedList = [...result].reverse();
    res.render("z-board/list.html", { boardList: reversedList });
}

exports.getWrite = (req, res)=>{
    res.render("z-board/write.html");
}

exports.getView = (req, res)=>{
    const index = req.query.index;
    if (index < 0 || index >= boardList.length) {
      // 에러 방지용 빈 페이지 띄우기
      return res.render("z-board/view.html", { boardItem: {} });
    }
    const boardItem = boardList[index];
    boardItem.hit += 1;
    res.render("z-board/view.html", { boardItem, boardList });
}

exports.getModify = (req, res) =>{
    const index = req.query.index;
    const boardItem = boardList[index];

    res.render("z-board/modify.html", { boardItem, index });
}

exports.postList = (req, res)=>{
    res.redirect("/board/z-board/list");
}

exports.postWrite = (req,res)=>{
    const boardItem = req.body;
    boardList.push(boardItem);

    const getTimeNow = (date) => {
    let mm = date.getMonth() + 1; // 0 ~ 11
    mm = (mm > 9 ? "" : "0") + mm; // 01 02...09 10 11
    let dd = date.getDate(); // 1 ~ 31
    dd = (dd > 9 ? "" : "0") + dd;
    let yy = date.getFullYear();

    let hr = date.getHours()
    let min = date.getMinutes()
    let sec = date.getSeconds()
    return [yy, mm, dd].join("-")+"."+[hr, min, sec].join(".")
    };

    boardItem.date = getTimeNow(new Date());
    boardItem.hit = -1;
    boardItem.idx = boardList.length - 1;

    res.redirect(`/board/z-board/view?index=${boardItem.idx}`);
}

exports.postView = (req, res) =>{

}

exports.postModify = (req, res) =>{
    const index = req.query.index;
    const boardItem = boardList[index];
    boardItem.subject = req.body.subject;
    boardItem.writer = req.body.writer;
    boardItem.content = req.body.content;

    res.redirect("/board/z-board/view?index=" + index);
}

exports.postDelete = (req, res) =>{
    const index = req.body.index;
    boardList.splice(index, 1);
    res.redirect("/board/z-board/list");
}

3) server 파일

[server.js]

const express = require("express");
const app = express();
const nunjucks = require("nunjucks");
const router = require("./routes")
const PORT = process.env.SERVER_PORT || 3000;

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(router)

app.listen(PORT, () => {
  console.log("server start");
});

*서버와 라우터는 최대한 간결하게 작성할 것!

0개의 댓글