1. express 서버 구성
프로젝트를 진행할 폴더를 생성하고, npm init을 통해 npm 모듈을 위한 베이스를 구성한다. 템플릿은 ejs를 사용할 것이다. ejs는 html에서 javascript를 사용하여 dynamic page를 구현할 수 있게 해주는 모듈이다. Embedded JavaScript template의 줄임말이다!
그 뒤, express 서버 구성을 위한 기본적인 npm 모듈을 다운받는다.
$ npm i express express-session ejs ejs-mate dotenv
5개의 패키지를 다운받았다. express와 express-session은 express 서버를 쓰기 위함이고, ejs와 ejs-mate는 앞서 설명한 dynamic html을 위해, 그리고 dotenv는 공개 소스코드로부터 숨기고싶은 value값이 있을 때를 위해(각종 configuration의 secret, ajax 통신에서 url 등) 필요한 모듈이다.
! session이란? 서버에서 저장하는 user-specific한 정보이다. 서버는 유저의 req cookie에 담긴 Session ID를 확인한 뒤 그에 맞는 서버의 session data를 구성해 유저에게 맞는 컨텐츠를 제공한다.
추가로! 소스코드가 수정될 때마다 자동으로 프로그램을 재시작해주는 nodemon 모듈도 다운받는게 좋다. 그때그때 node app.js를 할 수도 있지만 이게 여간 귀찮은게 아니다.... nodemon은 node로 진행하는 프로젝트에서 거의 다 쓰인다고 보면 되기 때문에 -g 옵션을 붙여 다운받는다.
$ npm install nodemon -g
그리고 폴더에 app.js파일을 추가하여 아래 코드를 입력했다.
const express = require("express");
const app = express();
const path = require("path");
const ejsMate = require("ejs-mate");
const session = require("express-session");
require("dotenv").config();
const port = 3000;
// Basic Setting
app.set("view engine", "ejs");
app.set("views", __dirname + "/views");
app.engine("ejs", ejsMate);
app.use(express.static(path.join(__dirname, "public")));
// session
const sessionConfig = {
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
expires: Date.now() + 1000 * 60 * 60 * 24 * 7,
maxAge: 1000 * 60 * 60 * 24 * 7,
},
};
app.use(session(sessionConfig));
app.get("/", (req, res) => {
res.render("home", { name: "부추" });
});
app.listen(port, () => {
console.log(`식단관리 프로젝트가 ${port}번 포트에서 시작합니다.`);
});
일단 필요한 모듈을 require한 뒤, express app을 구축하고 각종 configuration을 해줬다.
express app의 view engine을 ejs로 설정했고, ejs파일을 저장할 폴더를 "views"로 설정했다. 페이지 렌더링을 위한 ejs파일은 프로젝트의 "views"폴더를 추가하여 그 안에 전부 넣으면 된다. 그리고 추가 ejs 엔진으로 ejs-mate를 추가해주고(partial과 layout등을 이용하기 위함), 언젠가 static파일을 저장할 곳이 필요할 때를 위해 public폴더를 static으로 설정했다.
! static(정적) 파일이란? 이미지 / css 파일 등 값에 변화가 일어나지 않는 파일을 의미한다.
그 뒤, session을 이용하기 위해 session configuration 후 express app에 붙여주었다. session config object 구성 방법 및 내용은 공식 문서에 전부 나와있고, 나는 가장 보편적인 값들을 활용했다.
express-session
Simple session middleware for Express. Latest version: 1.17.3, last published: 2 months ago. Start using express-session in your project by running `npm i express-session`. There are 4305 other projects in the npm registry using express-session.
www.npmjs.com
app.get()은 서버가 받을 url의 이름과 url을 받은 뒤 실행할 각종 middleware함수들의 나열로 구성된다. 일단 request에 대해 아무런 조치를 취하지 않고 res.render(<filename>,<object>)을 이용해 home.ejs를 render하기로 했다.
views 폴더에 home.ejs를 추가하고 다음과 같이 작성한다. ejs 템플릿을 이용했다.
<h1>
안녕하세요, <%=name%>님!
</h1>
마지막으로 app.listen으로 지정한 포트에서 서버를 연다. nodemon을 사용하자.
$ nodemon app.js
서버 연결 성공 시에 app.listen의 콜백이 실행되어 콘솔에 로그가 찍히게 되고, 브라우저에서 localhost:3000으로 접속하면 res.render을 통해 보낸 object가 잘 도착한 것을 확인할 수 있다.
2. mongoDB와 model 구성
원래는 Mongo를 로컬에 다운받아서 mongosh를 돌린 뒤 ODM으로 mongoose를 사용했다. 나는 맥 노트북을 사용하고 있고 맥에서 mongoDB를 다운받는 문서 링크는 아래에 있다. 여기에 나온 instruction을 천천히 따라하면 로컬에 mongoDB를 다운받고 서버를 켜도록 하자.
https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-os-x/
Install MongoDB Community Edition on macOS — MongoDB Manual
Docs Home → MongoDB ManualMongoDB AtlasMongoDB Atlas is a hosted MongoDB service option in the cloud which requires no installation overhead and offers a free tier to get started.Use this tutorial to install MongoDB 6.0 Community Edition on macOS using t
www.mongodb.com
ODM이란? Object-Data-Mapping의 약자로, 프로그래밍에 사용되는 object와 mongoDB의 Data를 매핑시켜주는 라이브러리이다. 자바스크립트 환경에서 mongoDB를 사용한다면 ODM으로 거의 대부분 mongoose를 사용한다. 공식 문서 링크.
Mongoose ODM v6.4.6
Let's face it, writing MongoDB validation, casting and business logic boilerplate is a drag. That's why we wrote Mongoose. const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/test'); const Cat = mongoose.model('Cat', { name:
mongoosejs.com
프로젝트 DB구성에 필요한 기본적인 npm 모듈을 다운받는다.
$ npm install mongoose joi
joi는 schema validation tool이다. 프로젝트로 diet(식단), user(사용자), food(음식) 3개의 모델을 만들건데 사용자가 이 세 가지 모델 관련 입력을 줄 때마다 입력이 형식에 맞는지 확인하기 위해 사용할 것이다. joi 공식문서 링크!
joiSite
## Build Setup
joi.dev
이제 mongoose를 이용해 우리의 로컬 mongoDB 환경에 연결하기 위해 app.js에 다음의 코드를 추가한다.
const mongoose = require("mongoose");
mongoose
.connect("mongodb://localhost:27017/foodApp")
.then(() => {
console.log("식단관리 DB에 연결되었습니다!");
})
.catch((err) => {
console.log("DB 연결중 문제가 발생했습니다...");
console.log(err);
});
27017은 mongoDB에서 DB 구성 및 연결을 위해 사용하는 로컬 포트번호이다. 그 뒤 저장하고 app.js를 실행하면 따로 이슈가 없는 한, DB 연결 성공했다는 로그가 찍힐 것이다.
나는 프로젝트에 3가지 모델을 만들 것이다. 프로젝트 루트 폴더에 models 폴더를 추가하고 diet.js, food.js, user.js 파일을 추가했다. 그리고 mongoose 공식 문서가 안내한대로 모델 구조를 작성했다.
user은 이름만 보면 알 수 있듯 사용자에 관한 기본적인 정보(이름, 이메일, 비밀번호, 나이, 몸무게, 키 등등)를 담고 있다. food는 음식의 정보를 담는 모델로, 음식 이름, 설명, 각종 영양정보 등을 담고있다. diet는 특정 user와 그 user가 아침/점심/저녁/간식으로 먹은 food의 정보를 담고있는 모델이다. RDB에서 relation table이라고 보면 될까?
아무튼. 예시로 food.js 폴더에 food schema를 구성해보도록 하겠다. mongoose 공식 문서를 참고했다.
const mongoose = require("mongoose");
const { Schema } = mongoose;
const foodSchema = new Schema({
name: {
type: String,
required: true,
unique: true,
},
calories: {
type: Number,
required: true,
},
carbs: {
type: Number,
required: true,
},
sugar: { type: Number, default: 0 },
protein: {
type: Number,
required: true,
},
fat: {
type: Number,
required: true,
},
saturated: { type: Number, default: 0 },
serving: {
type: String,
enum: ["g", "개", "회"],
required: true,
},
amount: {
type: Number,
required: true,
},
description: String,
});
module.exports = mongoose.model("Food", foodSchema);
참고) saturated는 포화지방이다.
단위와 단위당 양까지 저장한 뒤, 모델을 구성해 export해줬다. 이제 이 모델은 mongo food모델이 필요한 여기저기에 활발하게 쓰일 것이다. 나머지 user, diet도 비슷하게 구성하면 된다.
그리고 schema validation을 위해 joi 모듈을 이용해보겠다. 방금 만든 mongoose의 food모듈은 validate tool로서 부실한 점이 너무 많다. 직접 model을 생성하기 전에 먼저 validation 진행 과정이 필요하다. 프로젝트 루트 폴더에 utils폴더를 추가하고, validateSchema.js에 다음의 joi validate 코드를 작성했다.
const Joi = require("joi");
module.exports.foodSchema = Joi.object({
name: Joi.string().min(1).max(30).required(),
calories: Joi.number().min(0).max(10000).required(),
carbs: Joi.number().min(0).max(10000).required(),
sugar: Joi.number().min(0).max(Joi.ref("carbs")).allow("", null),
protein: Joi.number().min(0).max(10000).required(),
fat: Joi.number().min(0).max(10000).required(),
saturated: Joi.number().min(0).max(Joi.ref("fat")).allow("", null),
serving: Joi.string().valid("g", "개", "회").required(),
amount: Joi.string().min(1).required(),
description: Joi.string().max(2000),
});
코드를 읽어보면 object의 각 attribute마다 어떤 제약조건이 있는지 확인할 수 있을 것이다. 전부 다 공식문서를 참고했다.
food와 마찬가지로 user, diet 역시 비슷한 식으로 구성했다. 모두 설명하기엔 포스트가 심히 길어질 것 같아 패스!
3. mongo Atlas 구성
보통 개발단계에선 로컬환경의 mongosh를 이용해 개발을 진행하지만 이왕 DB구성을 설명한 김에 아예 퍼블릭 DB까지 구성해보도록 하겠다.
mongoDB의 홈페이지에 들어가 sign in 한다.(계정이 없으면 가입한다)
그럼 mongo가 제공하는 db cloud의 어떤걸 쓸건지 묻는 페이지가 나오는데, 우리는 당연히! free shared를 쓸 것이다.
그 뒤 기본적인 configuration을 진행하는 페이지로 가게되는데, 나는 배포에 AWS를 이용할 것이고 서울에 살고 있으니 그냥 아무것도 건들지 않았다.
저장용량을 얼마나 할 것인지, cloud cluster 이름은 어떻게 할 것인지 기타 설정은 알아서 하면 된다.
create cluster을 누르면 DB 접근과 관련된 configuration이 시작된다. auth를 위해선 아이디/비번을 사용할 것인지, 특정 인증서를 사용할 것인지 고르게 되는데 지금은 그냥 간단하게 아이디와 비번을 사용하도록 하겠다. 원하는 username(ID)와 password를 작성하도록 하자.
그리고 DB접근을 허용할 IP address를 설정하게된다. 이 프로젝트에서는 내 로컬 컴퓨터 + EC2로 구성한 서버 만이 DB에 접근할 것이므로 My Local Environment에 "Add My Current IP Address"만을 해주고 넘어가도록 한다.
그 뒤 create를 클릭하면!
이렇게 성공적으로 DB cloud가 생성된 것을 볼 수 있다. 이제 우리의 프로젝트 환경에서 이렇게 생성한 DB를 연결해보도록 하겠다. 위 페이지에서 "Connect"버튼을 클릭한다.
첫번째 옵션은 mongosh와 같은 방법으로 cloud DB에 접근할 수 있는 방법이다. 옵션을 클릭한 뒤 받게되는 command line을 터미널에 그대로 복붙하면 DB에 접근할 수 있게 된다. db CRUD를 위한 커맨드는 mongosh를 이용할 때와 100% 같다.
두번째 옵션이 우리가 원하는 옵션이다. connect your application을 클릭한 뒤 deriver에 node.js를 선택하면 connection string을 받을 수 있다.
안내한대로 string의 <password>부분을 우리가 좀전에 설정한 비밀번호로 대체한다. 그리고 app.js에서 mongoose.connect의 parameter에 방금 구성한 connection string을 넣는다.
mongoose
.connect("<방금 구성한 connection string>")
.then(() => {
console.log("식단관리 DB에 연결되었습니다!");
})
.catch((err) => {
console.log("DB 연결중 문제가 발생했습니다...");
console.log(err);
});
그 뒤 app.js를 실행하면 큰 이슈가 없는 한.. 방금 과정을 통해 구성한 mongoDB cloud와 연결이 완료되었을 것이다!
4. bootstrap 및 ejs-mate
기본적인 프런트 레이아웃을 구성하기 위해 bootstrap을 사용하였다.
Get started with Bootstrap
Bootstrap is a powerful, feature-packed frontend toolkit. Build anything—from prototype to production—in minutes.
getbootstrap.com
CDN link를 이용해 head의 link 태그에 CSS 주소를, script의 src에 JS 주소를 넣었다. navbar, button, form 구성 등은 모두 부트스트랩 공식문서의 docs를 참고했다. d-flex, row, col 등등 grid와 box 관련한 요소도 마구마구 사용했다.
그리고 layout, partials 등을 구성하기 위해서 ejs-mate 모듈을 사용했다. 앞서 app.js에 app.engine("ejs",ejsMate) 코드를 붙인건 이를 위함이다. views 폴더에 partials, layouts 폴더를 추가하고 필요한 여러가지 partial(navbar, footer, flash...)등을 구성하고 boilerplate를 작성했다.
ejs-mate
Express 4.x locals for layout, partial.. Latest version: 4.0.0, last published: 2 months ago. Start using ejs-mate in your project by running `npm i ejs-mate`. There are 24 other projects in the npm registry using ejs-mate.
www.npmjs.com