🎩 requirement
MySQL, sequelize에 대한 이해
https://darrengwon.tistory.com/146?category=858366
HeidiDB와 mysql 모델을 이용해서 AWS RDS와 연동하기
https://darrengwon.tistory.com/240
mongoDB, mongoose에 대한 이해
https://darrengwon.tistory.com/188
node.js의 기본 모듈과 express-generator가 생성하는 폴더, 파일에 대한 역할 이해
https://darrengwon.tistory.com/139?category=858366
express에서 router 이용
https://darrengwon.tistory.com/46?category=858366
ES6 JS 문법과 이를 실행하기 위한 babel 설치
https://darrengwon.tistory.com/29?category=858365
https://darrengwon.tistory.com/12
dotenv 활용
https://darrengwon.tistory.com/171
세션, 쿠키에 대한 이해
https://darrengwon.tistory.com/185?category=858372
https://darrengwon.tistory.com/186?category=858366
express를 활용한 웹 백엔드 설계 순서
🎩 설치 및 DB 세팅
🎩 DB 만들기
🎩 app.js에서 사용할 미들 웨어 설치 후 app.js 코딩
🎩 router와 view 세팅
🎩 필요한 DB 테이블 정의 및 생성
🎩 passport.js로 로그인 기능 구현 (+ federated id)
🎩 코드 배포용으로 전환하기
🎩 배포
🎩 설치 및 DB 세팅
npm init
npm i nodemon babel @babel/core @babel/preset-env @babel/node
npm i sequelize mysql2
npm i -g sequelize-cli
npm i express dotenv
sequelize init
MySQL을 사용하기 위한 폴더가 자동 생성 됩니다.
🎩 DB 만들기
config.json에서 DB pw, 이름(database) 등 설정
{
"development": {
"username": "root",
"password": "1111",
"database": "twitter",
"host": "xxx.xxx.xxx.xxx",
"dialect": "mysql",
"operatorsAliases": false
},
sequelize db:create
이후 명령창에서 mysql -h [접속할 주소] –u[사용자아이디] -p[비밀번호]로 접속 가능합니다.
🎩 app.js에서 사용할 미들 웨어 설치 후 app.js 코딩
npm i cookie-parser express-session morgan connect-flash helmet pug
다음은 app.js의 전반적인 모습입니다.
import express from "express";
import cookieParser from "cookie-parser";
import morgan from "morgan";
import path from "path";
import session from "express-session";
import flash from "connect-flash";
import dotenv from "dotenv";
import connect from "./db"; // mongoDB를 사용하면 연결해둡시다.
import webSocket from "./socket"; // socket.IO 쓸거면 연결해둡시다.
import router from "./routes/index";
// using dotenv
dotenv.config();
const app = express();
// mongoDB 연결
connect();
//view engine
app.set("views", path.join(__dirname, "views")); //views 폴더 생성해야 함
app.set("view engine", "pug");
//middleware
app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public"))); //static 정보처리. public 폴더 생성해야 함
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
secret: process.env.COOKIE_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
httpOny: true,
secure: false
}
})
);
app.use(flash());
//router
app.use("/", router);
// 404 handling
app.use((req, res, next) => {
const err = new Error("Not Found");
err.status = 404;
next(err);
});
// Error handling
app.use((req, res, err) => {
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
res.status(err.status || 500);
res.render("error");
});
// listen
const server = app.listen(process.env.PORT, () => {
return console.log(`success on : http://localhost:${process.env.PORT}`);
});
// 소켓을 쓸거면 server와 연동
webSocket(server);
app.js에서 입력한대로 views와 public 폴더를 생성합니다.
🎩 router와 view 세팅
app.js에서 app.get("/", (req, res) => "yeah") 로 계속 라우터 처리를 할수는 없습니다. 라우터 폴더를 따로 만든 후에 처리하도록 합시다. 아직 controller 단으로 구별하지는 않았습니다. 또, 렌더하는 함수에 각종 변수를 전달할수도 있음을 기억합시다
import express from "express";
import db from "./models";
import cookieParser from "cookie-parser";
import morgan from "morgan";
import path from "path";
import session from "express-session";
import flash from "connect-flash";
import dotenv from "dotenv";
import router from "./routes/index";
// using dotenv
dotenv.config();
//mysql 연동
db.sequelize.sync();
const app = express();
//view engine
app.set("views", path.join(__dirname, "views")); //views 폴더 생성해야 함
app.set("view engine", "pug");
//middleware
app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public"))); //public 폴더 생성해야 함
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
session({
secret: process.env.COOKIE_SECRET,
resave: false,
saveUninitialized: true,
cookie: {
httpOny: true,
secure: false
}
})
);
app.use(flash());
//router
app.use("/", router);
// 404 handling
app.use((req, res, next) => {
const err = new Error("Not Found");
err.status = 404;
next(err);
});
// Error handling
app.use((req, res, err) => {
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
res.status(err.status || 500);
res.render("error");
});
// listen
app.listen(process.env.PORT, () => {
return console.log(`success on : http://localhost:${process.env.PORT}`);
});
app.js와 연결해줍니다
import router from "./routes/index";
... 중략
//router
app.use("/", router);
🎩 필요한 DB 테이블 정의 및 생성
앞서 sequelize로 생성된 여러 폴더와 파일중 models 폴더에 테이블로 사용할 js 파일들을 생성하고, 이를 models/index.js에 연결합니다. 물론 이 index 는 app.js에 연결해야 합니다.
1️⃣ 테이블 작성
export default (sequelize, DataTypes) => {
return sequelize.define(
"user",
{
email: {
type: DataTypes.STRING(40),
allowNull: false,
Unique: true
},
nick: {
type: DataTypes.STRING(15),
allowNull: false
},
password: {
type: DataTypes.STRING(100),
// social login시 비밀 번호가 없기 때문에 null을 허용해야 합니다
allowNull: true
},
provider: {
type: DataTypes.STRING(10),
allowNull: false,
defaultValue: "local"
},
snsId: {
type: DataTypes.STRING(30),
allowNull: true
}
},
//timestamps는 생성일과 수정일, paranoid는 삭제일(복구용)입니다
// charset과 collate를 다음과 같이 해야 한글이 깨지지 않습니다.
{ timestamps: true, paranoid: true, charset: 'utf8', collate: 'utf8_general_ci' }
);
};
2️⃣ models/index.js 에 삽입
//index.js
import path from "path";
import Sequelize from "sequelize";
import user from "./user";
import post from "./post";
import hashtag from "./hashtag";
const env = process.env.NODE_ENV || "development"; //실제 출시할 때 production로 변경.
const config = require("../config/config.json")[env]; //config.json 객체에서 [env] 선택
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
const db = {}; //db라는 객체를 만들고 모듈로 활용
db.Sequelize = Sequelize;
db.sequelize = sequelize;
const User = user(sequelize, Sequelize);
const Post = post(sequelize, Sequelize);
const Hashtag = hashtag(sequelize, Sequelize);
// 1개의 User는 여러 개의 Post를 가지고 있는 1:N 관계
User.hasMany(Post);
Post.belongsTo(User);
// Post와 HashTag는 다대다 관계입니다.
// through에는 새로 생기는 모델(매칭 테이블)의 이름을 지정합니다.
Post.belongsToMany(Hashtag, { through: "PostHashTag" });
Hashtag.belongsToMany(Post, { through: "PostHashTag" });
// User 간 팔로우는 같은 테이블간 다대다입니다.
// as는 Join 작업시 사용하는 이름이며 foreignKey는 참고하는 외래키입니다.
// 팔로워는 팔로잉의 id를 참고하고 팔로잉은 팔로워의 id를 참고합니다.
User.belongsToMany(User, {
through: "Follow",
as: "Followers",
foreignKey: "followingId"
});
User.belongsToMany(User, {
through: "Follow",
as: "Following",
foreignKey: "followerId"
});
// User가 Like하는 Post는 다대다 관계입니다
User.belongsToMany(Post, { through: "Like" });
Post.belongsToMany(User, { through: "Like" });
export default db;
3️⃣ app.js에 연결
import db from "./models";
//mysql 연동
db.sequelize.sync();
연결을 완료하면 다음과 같이 config/config.json에서 등록한 DB의 이름 아래 테이블이 생성되어 있음을 확인할 수 있습니다.
MySQL이 아닌 mongoDB를 사용하고 싶으면 다음 게시물을 참고합시다.
https://darrengwon.tistory.com/188
또, Sequelize와 같은 ORM이 아니라 SQL로 작성하고 싶다면(또, AWS RDS를 이용할 것이라면) 아래 포스트를 참고합시다. 저는 이 방법이 더 맞다고 생각하는 편입니다.
https://darrengwon.tistory.com/240
🎩 passport.js로 로그인 기능 구현 (+ federated id)
https://darrengwon.tistory.com/195
https://darrengwon.tistory.com/211?category=858366
🎩 코드 배포용으로 전환하기
🎩 배포
AWS나 GCP와 같은 클라우드 플랫폼을 통해 배포하는 것을 선호한다. AWS를 기준으로 이야기하자면, EC2를 하나 만든 후 node.js 등 이용한 것들을 설치한 후 git clone을 통해 작성한 코드를 불러온 다음 dependencies를 설치하고 DB를 시작한 후 배포하면 된다.
처음 EC2를 시작하면 아무 것도 들지 않은 깡통을 받는 것이기 때문에 node 부터 설치해서 구동에 필요한 것들을 일일히 설치해야 한다.
https://github.com/nodesource/distributions
* ubuntu 환경에서 설치
sudo apt-get update
sudo apt-get install build-essential
sudo apt-get curl
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - // 위 사이트에 가서 원하는 버전으로 설치합니다 최근 이 코드가 말을 안 듣는 경우가 많아졌으니 설치가 안되면 위 사이트를 참고합시다.
sudo apt-get install -y nodejs // 노드가 설치됩니다. node -v와 npm -v를 확인해보세요
sudo npm i -g npm // npm update
mysql을 사용하시면 아래 코드를 입력합시다.
sudo apt-get install -y mysql-server // 설치 직후 mysql 비밀번호 등록이 나옵니다. 소스 코드에 적은 대로 적읍시다.
mysql_secure_installation // mysql 설치 완료. mysql -h localhost -u root -p로 접속해봅시다
* git clone을 통해 불러온 소스코드가 있는 경로로 이동한 후
npm i //dependencies 설치
sudo npm i -g pm2 cross-env sequelize-cli // global하게 사용한 패키지들 설치
sequelize db:create --env production
* git에 올리지 않은 dotenv는 어떻게 하나요? => vim을 통해 직접 .env를 복붙합시다
npm start // 실행 완료 (혹, package.json의 script를 다른 걸로 작성했다면 그걸로 실행합니다)
* 같은 EC2에 DB 서버와 웹 서버가 동시에 있는 형국은 좋지 않다. 둘을 분리하는 것이 좋다. 서버 하나에 문제가 생겼을 때 다른 서버에 영향을 미치는 것을 막아야 하기 때문이다. RDS를 사용사던지 다른 EC2를 열어 따로 DB 서버를 운영하자.
'Node, Nest, Deno > 🚀 Node.js (+ Express)' 카테고리의 다른 글
npm 업데이트와 node 업데이트 (nvm, n) (0) | 2020.04.04 |
---|---|
Express 백엔드 배포용 전환 (morgan, pm2, winston) (0) | 2020.04.04 |
express-session을 통해 세션 사용하기 (3) | 2020.03.27 |
EJS 뷰 엔진 사용하기 (0) | 2020.03.12 |
PUG 뷰 엔진 마스터하기 (0) | 2020.03.12 |