이번주차의 과제는 간단하게 nodejs와 express를 사용하여 로그인 기능이 없는 CRUD 게시판을 만드는것이다.
실제로 구현까지 많은 시간이 걸리지 않았는데 배포부분은 아직도 잘 모르는것 투성이다.
하지만 늘 그랬듯, 잘하는것이 중요한게 아니라 꾸준히 알아가는것이 중요하기에
포기만 하지 않으면 된다.
이번 과제의 기본적인 구조는 간단한 디자인 패턴중 하나인 MVC모델을 전제로 가져가는것같다.
몇년전만 해도 MVC가 뭐가 뭔지도 몰랐는데 지금은 너무 간단하다고 생각되는 모델중 하나라니 참 감회롭긴 하다.
일단 가볍게 과제의 기본 세팅인 Express와, res.Body를 쉽게 파싱할 수 있도록 기본 골자를 짜고, 데이터 모델 역시 Connect로 선언해서 가져온다.
const express = require('express') const app = express(); app.use(express.json()); app.use(express.urlencoded({extended: true})); const connect = require('./schemas'); connect(); const boardRouter = require("./routers/board"); app.use('/api', [boardRouter]);
그리고 View로는 가볍게 템플릿 엔진인 ejs를 사용하여 보여주고, Controller부분인 API가 저장된 Router역시 선언해준다
app.set('views', __dirname + '/views'); //경로 설정 부분 app.set('view engine', 'ejs'); //view engine으로 ejs를 사용할것 app.get('/', (req, res) => { res.render('index');
index부분에서 바로 그냥 데이터베이스를 연결하는 로직을 적어줘도 되지만, 그건 너무
우아하지않다
뭐, 우아한건 둘째치고 나중에 수정할때도 불편할수 있으니
차라리 모듈로 빼는게 낫지않은가?
const mongoose = require("mongoose");
const connect = () => {
mongoose
.connect("mongodb://localhost:27017/board", {
useNewUrlParser: true,
ignoreUndefined: true
})
.catch(err => console.log(err));
};
mongoose.connection.on("error", err => {
console.error("몽고디비 연결 에러", err);
});
module.exports = connect;
그래서 위에서 선언한것처럼 module을 connect란 이름으로 exports한 후 index에서 해당 index를 가져와서 함수처럼 사용하기만 하면 끝이다.
또한 데이터베이스를 저장하거나 업데이트 할때, 매 번 데이터베이스의 속성을 선언하고~ 거기에 저장하고~ 할 필요가 많기 때문에 스키마 모델 부분 역시 따로 빼두는게 좋다
const mongoose = require("mongoose");
const { Schema } = mongoose;
const boardSchema = new Schema({
///스키마 속성들...
});
module.exports = mongoose.model("board", boardSchema);
이런식으로 말이다.
나중에 해당 스키마를 가져올때는 그냥 해당 스키마의 위치와 export한 이름을 적어주면 끝이다
const Board = require('../schemas/board');
app.get('/', (req, res) => {
res.render('index');
})
처음 접속하게되면 View 화면인 index.ejs를 그려주고,
//index.ejs
$(document).ready(function () {
get_list();
})
에선 get_list()란 함수를 페이지 로딩이 끝나고 요청하게된다.
const get_list = () => {
$('#boardList').empty();
$.ajax({
type: "GET",
url: `/api/lists`,
data: {},
success: function (response) {
let lists = response["lists"]
for (let i = 0; i < lists.length; i++) {
make_list(lists[i], lists.length-i)
}
}
})
}
해당 함수는 컨트롤러에 /api/lists라는 api를 요청하게 되는데,
/api로 시작하기에 routers/board라는 라우터를 사용하게 된다.
const router = express.Router();
router.get("/lists", async (req, res, next) => {
try {
const lists = await Board.find({showing: 1}).sort("-postId");
res.json({ lists: lists });
list api는 요청이 성공적으로 마무리 됫을경우 response에 json파일로 요청한 데이터를 넘겨주게되고, 위의 get_list가 json파일을 받아 화면에 그려주게 된다.
이 얼마나 아름답고 간결하고 완벽한 일련의 동작인지...
이맛에 다들 api를 하는게 아닐까?
비밀번호같은 경우에는 그냥 귀찮아서 대강 박아 넣으려다가,
그래도 명색이 비밀번호인데 해쉬처리는 좀 해줘야 하지 않겠는가?
비밀번호같은 경우에는 가볍게 bcrypt모듈을 이용하여 구현하였다.
const bcrypt = require('bcrypt');
...
const encryptedPassowrd = bcrypt.hashSync(password, 10);
....
bcrypt.compare(password, posted['password'], function(err, msg){
if(msg === true){
console.log('비번맞음');
res.send({ result: "success" });
}
else{
res.send({ result: "fail" });
}
})
이쁘게 해시값으로 변환되고, 원래 비밀번호하고 비교했을때 동일하다면 수정, 삭제가 가능하도록, 그렇지 않다면 Alert창을 띄우도록 했다.
가볍게 해쉬처리를 하게 만들어준다는게 참 신기할 따름이다
여담이지만, 처음 비밀번호를 비교하려 했을때 무의식적으로 비밀번호를 '보내준다' 는 생각 대신 비교한 값을 '받아준다' 라는 개념으로 생각하여 Post로 입력한 비밀번호를 보내주는게 아니라 get으로 입력한 비밀번호를 보내주어 작동이 안되서 30분동안 끙끙댄적이 있다.
정말 당혹스러운 경험이였다
이전에 만들어놓은 ec2 인스턴스에 이번 과제를 올리려햇는데 이게 뭘 잘못햇는지 몽고디비도 안되고, 모듈도 잘 안깔리고, npm도 안먹혓다.
그래서 별수없이 새로 프리티어를 하나 사서 거기에 올리니 한방에 해결됬다.
나중에... 진짜 좀 이친구좀 손봐야할것같다
기본적인 개념이 조금 부족한것 같으니 다른 강의들도 조금씩 보며 좀더 머릿속의 개념을 확립시키는것이 중요한것같다.
한걸음씩 꾸준히, 잘하는것이 중요한게 아니라 꾸준한것이 중요하다