주소록 - Module만들기

소스코드

이 게시물에는 코드작성이 포함되어 있습니다. 소스코드를 받으신 후 진행해 주세요. MEAN Stack/개발 환경 구축에서 설명된 프로그램들(git, npm, atom editor)이 있어야 아래의 명령어들을 실행할 수 있습니다.

이 게시물의 소스코드는 주소록 만들기 / 주소록 - Show, Edit, Update, Destroy에서 이어집니다.

contact-book.git 을 clone 한 적이 있는 경우: 터미널에서 해당 폴더로 이동 후 아래 명령어들을 붙여넣기합니다. 폴더 내 모든 코드가 이 게시물의 코드로 교체됩니다. 이를 원치 않으시면 이 방법을 선택하지 마세요.

git reset --hard
git pull
git reset --hard c0a751b
git reset --soft 26718b1
npm install
atom .

contact-book.git 을 clone 한 적이 없는 경우: 터미널에서 코드를 다운 받을 폴더로 이동한 후 아래 명령어들을 붙여넣기하여 contact-book.git 을 clone 합니다.

git clone https://github.com/a-mean-blogger/contact-book.git
cd contact-book
git reset --hard c0a751b
git reset --soft 26718b1
npm install
atom .

- Github에서 소스코드 보기: https://github.com/a-mean-blogger/contact-book/tree/c0a751bb74412a025b140b590e575c2704ddf0ec


지금까지 주소록 강좌에서는 index.js파일 하나에 모든 서버 코드들을 작성해 왔습니다.
주소록 사이트는 서버코드가 100줄이 안되는 간단한 사이트라 하나의 파일에 모든 코드들을 작성해도 별로 불편함이 없지만, 코드가 길어지면 파일을 나누는 것이 개발에 효율적입니다.
이번 포스팅에서는 modelroutemodule로 분리하여 코드를 정리해봅시다. 기능상의 차이는 전혀 없습니다.

폴더구조

주황색은 변경된 파일, 녹색은 새로 생성된 파일, 회색은 변화가 없는 파일입니다.

index.js의 코드에서 Contact model을 때어내서 models/Contact.js로, contact route을 때어내서 routes/contacts.js, home route을 때어내서 routes/home.js로 이동하였습니다.

코드

//index.js

var express = require("express");
var mongoose = require("mongoose");
var bodyParser = require("body-parser");
var methodOverride = require("method-override");
var app = express();

// DB setting
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
mongoose.connect(process.env.MONGO_DB);
var db = mongoose.connection;
db.once("open", function(){
  console.log("DB connected");
});
db.on("error", function(err){
  console.log("DB ERROR : ", err);
});

// Other settings
app.set("view engine", "ejs");
app.use(express.static(__dirname+"/public"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(methodOverride("_method"));

// Routes
app.use("/", require("./routes/home")); //1
app.use("/contacts", require("./routes/contacts")); //2

// Port setting
var port = 3000;
app.listen(port, function(){
  console.log("server on! http://localhost:"+port);
});

DB schema, routes 부분의 코드가 없어지고 routes에는 app.use가 추가되었습니다.분리된 routes은 index.js의 app.use 안에서 직접 require를 하고 있고 DB schema는 route안에서만 사용되기 때문에 index.js에서는require를 하지 않고, 해당 route안에서require됩니다.

1 & 2. app.use("route", 콜백_함수)는 해당 route에 요청이 오는 경우에만 콜백 함수를 호출합니다.

다음으로 route 파일들을 봅시다.

//routes/home.js

var express = require("express");
var router = express.Router(); //1

// Home 
router.get("/", function(req, res){ //2
  res.redirect("/contacts");
});

module.exports = router; // 3

위에서 app.use는 route콜백 함수를 받는다고 했는데, 우리가 사용할 콜백 함수는 express가 제공하는 router함수 입니다.

1. express.Router()를 사용해서 router함수를 초기화합니다.

2. app.get에서 router.get으로 바뀐 것만 빼면 이전코드와 동일합니다. "/"에 get 요청이 오는 경우를 router함수에 설정해 줍니다.

3. module.exports에 담긴 object(여기서는 router object)가 module이 되어require시에 사용됩니다.

// routes/contacts.js

var express = require("express");
var router = express.Router();
var Contact = require("../models/Contact"); //1

// Index
router.get("/", function(req, res){
  Contact.find({}, function(err, contacts){
    if(err) return res.json(err);
    res.render("contacts/index", {contacts:contacts});
  });
});

// New
router.get("/new", function(req, res){
  res.render("contacts/new");
});

// create
router.post("/", function(req, res){
  Contact.create(req.body, function(err, contact){
    if(err) return res.json(err);
    res.redirect("/contacts");
  });
});

// show
router.get("/:id", function(req, res){
  Contact.findOne({_id:req.params.id}, function(err, contact){
    if(err) return res.json(err);
    res.render("contacts/show", {contact:contact});
  });
});

// edit
router.get("/:id/edit", function(req, res){
  Contact.findOne({_id:req.params.id}, function(err, contact){
    if(err) return res.json(err);
    res.render("contacts/edit", {contact:contact});
  });
});

// update
router.put("/:id", function(req, res){
  Contact.findOneAndUpdate({_id:req.params.id}, req.body, function(err, contact){
    if(err) return res.json(err);
    res.redirect("/contacts/"+req.params.id);
  });
});

// destroy
router.delete("/:id", function(req, res){
  Contact.deleteOne({_id:req.params.id}, function(err){
    if(err) return res.json(err);
    res.redirect("/contacts");
  });
});

module.exports = router;

1. contact.js에는 Contact modulerequire로 호출합니다.

2. 나머지는 역시 app.HTTP_METHOD 들이 router.HTTP_METHOD로 바뀌었습니다. 그리고 route 문자열에서 contacts가 빠졌는데(destroy를 예를들면 "contacts/:id"에서 "/:id"로 바뀌었습니다), index.js에서

app.use("/contacts", require("./routes/contacts"));

로 이미 "/contacts"인 경우에만 이 module이 호출되기 때문입니다.

// models/Contact.js

var mongoose = require("mongoose");

var contactSchema = mongoose.Schema({
  name:{type:String, required:true, unique:true},
  email:{type:String},
  phone:{type:String}
});

var Contact = mongoose.model("contact", contactSchema);

module.exports = Contact;

Contact를 module로 만들어서 사용하고 있습니다. 그 외 바뀐 코드는 없습니다.

마치며..

실행시 이전과 달라진 점은 없습니다. 단지 개발의 편의를 위해 코드 위치만 바꾼 것이라고 생각하시면 됩니다.
이 강좌에서는 강좌의 편의를 위해 처음에는 하나의 파일로 프로젝트를 작성하다가 어느정도 코드가 작성된 후 파일들을 분리했지만, 처음부터 파일들을 분할하여 작성하는 것이 바람직합니다. 저도 다음 강좌부터는 처음부터 파일을 분할하여 작성하겠습니다.
다음 강의에서는 드디어 주소록 사이트에 옷을 입혀 보겠습니다.

댓글

K
KimchiBlaster 2018.07.22
감사합니다 ^^
I
Ian H 2018.07.23
@KimchiBlaster,
읽어 주셔서 감사합니다^^
정재표 2018.11.29
res.render("contacts/index", {contacts:contacts}); 라는 문구가 어떤 뜻인가요?
contacts/index.ejs 를 render 보여주면서 까지는 이해했는데 뒤의 { 복수형 : 단수형 } 이런 파라메터 표기 법을 잘 모르겠습니다 
I
Ian H 2018.11.29
@정재표,
{복수형: 단수형}이 아니라 항상 {복수형:복수형} 혹은 {단수형:단수형}입니다. 만약 {복수형: 단수형}이라고 된 곳이 있다면 저의 실수입니다^^;
render 함수에는 두가지 변수가 전달되는데, 첫번째는 이해하고 계신 것 처럼 template 파일의 경로를 문자열로 전달받습니다.
두번째는 해당 template함수에서 사용될 데이터의 목록입니다. contacts/index.ejs 파일을 보시면 contacts라는 변수를 반목문에서 사용하고 있는데, 이걸 {contacts:contacts}로 받아서 template으로 전달하는 것입니다.
{   template에서_사용될_변수이름1: template으로_전달할_데이터1,    template에서_사용될_변수이름2: template으로_전달할_데이터2,    template에서_사용될_변수이름3: template으로_전달할_데이터3,   ... }
요런식으로 데이터를 template으로 전달합니다.
댓글쓰기

이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기

UP