1) Node.js
1-1) Back-end 구현(dotenv, config, 예외처리)
1-2) Back-end User Table 추가(ORM 적용: sequelize)
1) Node.js
1-1) Back-end 구현(dotenv, config, 예외처리)
| GET /comments
| GET /comments/:id
| POST /comments
| PUT /comments/:id
| DELETE /comments/:id
dotenv(.env) 라이브러리: 시스템 환경변수를 ".env 파일"을 읽어서 적용시키는 것을 의미함!
참고로 ".env 파일" 상의 "NODE_ENV=development"는 개발모드를 의미한다!!
Router --> Controller --> Service --> Repository --> pool
exceptions 디렉토리: 예외처리 역할
back
server.js
// require("dotenv").config;
// --> require를 통해 dotenv 파일을 가져와서 config를 호출하면 ".env 파일"을 읽고 해당 파일에서 변수를 읽고 시스템 환경변수(process.env)에 해당 변수값을 잠깐 넣어놓음!
// --> 이렇게 되면 "const PORT = process.env.PORT || 3000;"의 경우, "process.env" 객체의 PORT 변수에 ".env 파일"에서 지정한 PORT 값인 3001이 할당됨!!
const express = require("express");
const app = express();
const config = require("./config");
const HttpException = config.exception.HttpException;
// const PORT = process.env.PORT || 3000;
const router = require("./routes");
app.use(router);
app.use((error, req, res, next) => {
// 응답 코드 500
// if (error instanceof Error) {}
console.error(error);
if (error instanceof HttpException) {
res.json({
isError: true,
message: error.message,
status: error.status,
});
} else if (error instanceof Error) {
res.json({
isError: true,
message: error.message,
});
}
});
app.listen(config.port, async () => {
console.log(`server start ${config.port}`);
});
config.js
require("dotenv").config();
const HttpException = require("./exceptions/HTTPException");
const host = process.env.DB_HOST || "127.0.0.1";
const port = process.env.DB_PORT || 3306;
const user = process.env.DB_USER || "본인 MySQL user명";
const password = process.env.DB_PASSWORD || "본인 MySQL 비밀번호";
const database = process.env.DB_DATABASE || "comments";
const config = {
exception: {
HttpException,
},
port: process.env.PORT || 3000,
db: {
host,
port,
user,
password,
database,
},
};
module.exports = config;
exceptions/HTTPException.js
class HttpException extends Error {
constructor(message) {
super(message);
this.status = 500;
}
}
// const e = new HTTPException("요청 데이터가 없음!!", 500);
// console.log(e);
// console.log(e.message, e.status);
// console.log(typeof e); // "e"는 인스턴스화 된 것이기에 타입은 객체(object)이다!!
module.exports = HttpException;
routes/index.js
const express = require("express");
const router = express.Router();
const commentRouter = require("../comment/comment.route");
router.use("/comments", commentRouter);
module.exports = router;
routes/comment.route.js
const express = require("express");
const router = express.Router();
const { controller } = require("./comment.module");
router.get("/", (req, res, next) => controller.getList(req, res, next));
module.exports = router;
comment/comment.controller.js
class CommentController {
constructor({ commentService }) {
this.commentService = commentService;
}
async getList(req, res, next) {
try {
const comments = await this.commentService.list();
res.json(comments);
} catch (e) {
next(e);
}
}
}
module.exports = CommentController;
comment/comment.service.js
/*
module.exports = (repository) => {
return {
list: async () => {
const list = await repository.findAll();
return list;
},
};
};
*/
class CommentService {
constructor({ commentRepository, config }) {
this.commentRepository = commentRepository;
this.config = config;
this.HttpException = config.exception.HttpException;
}
async list() {
try {
const list = await this.commentRepository.findAll();
// if (list.length === 0) throw new Error("내용이 없음");
throw "내용이 없음";
return list;
} catch (e) {
// throw new Error(e);
throw new this.HttpException(e);
}
}
}
module.exports = CommentService;
comment/comment.repository.js
/*
module.exports = (mysql) => {
return {
findAll: async () => {
const result = await mysql.query("SELECT * FROM Comment");
return result;
},
};
};
*/
// 바로 아래의 CommentRepository class와 비슷한 원리의 생성자 함수
// function Repository(mysql) {
// // this = {}
// this.mysql = mysql;
// this.list = async () => {
// this.mysql;
// };
// // return this
// }
class CommentRepository {
constructor({ mysql }) {
this.mysql = mysql;
}
async findAll() {
try {
const [list] = await this.mysql.query("SELECT * FROM Comment");
return list;
} catch (e) {
throw new Error(e);
}
}
view() {}
update() {}
create() {}
}
module.exports = CommentRepository;
comment/comment.module.js
/*
const mysql = require("../models");
const repository = require("./comment.repository")(mysql);
const service = require("./comment.service")(repository);
const controller = require("./comment.controller")(service);
repository.findAll().then((data) => console.log(data));
service.list().then((data) => console.log(data));
*/
// 인스턴스를 생성해서 내보내주는 역할이 "comment.module.js"의 역할이다!!
const config = require("../config");
const mysql = require("../models");
const CommentRepository = require("./comment.repository");
const CommentService = require("./comment.service");
const CommentController = require("./comment.controller");
const repository = new CommentRepository({ mysql });
const service = new CommentService({ commentRepository: repository, config });
const controller = new CommentController({ commentService: service });
// repository.findAll().then((data) => {
// console.log(data);
// });
// service.list().then((data) => {
// console.log(data);
// });
module.exports = {
repository,
service,
controller,
};
models/index.js
// require("dotenv").config();
const mysql = require("mysql2");
const config = require("../config");
// const host = process.env.DB_HOST || "127.0.0.1";
// const port = process.env.DB_PORT || 3306;
// const user = process.env.DB_USER || "본인 user명";
// const password = process.env.DB_PASSWORD || "본인 MySQL 비밀번호";
// const database = process.env.DB_DATABASE || "comments";
const pool = mysql.createPool(config.db).promise();
// const pool = mysql
// .createPool({
// host,
// port,
// user,
// password,
// database,
// })
// .promise();
// pool.query("SELECT * FROM Comment").then((data) => console.log(data));
module.exports = pool;
.env
PORT=3001
NODE_ENV=development
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=본인 user명
DB_PASSWORD=본인 MySQL 비밀번호
DB_DATABASE=comments
1-2) Back-end User Table 추가(ORM 적용: sequelize)
ORM
정의: "Object Relational Mapping"이라는 의미로, 데이터베이스 상의 데이터를 "Table" 형태로 저장하는 "RDBMS"와
실제 application layer에서 작업하여 요청 및 응답을 처리해주는 Web Server의 경우
Table 형태의 데이터를 객체(Object) 형태로 사용하여 데이터를 조작하게 된다.
이때 기존의 RDBMS처럼 Table을 만들어서 거기에 객체를 담는 것이 아니라
객체로 Table을 생성하면서 관리하는 것이 더 편하지 않을까하는 관점에서 등장한 것이
바로 "ORM"이라 볼 수 있다.
즉, RDBMS가 SQL 문법을 통해 Table을 생성하고, 각 Record를 추가/조회/수정/삭제하였는데
이를 객체로 관리한다고 하는 것이 "ORM"이라 할 수 있다!
ORM 설정: 이는 "SQL 구문을 사용하지 않을 수도 있다"라는 의미이다!
CREATE TABLE User(
id int(11) PRIMARY KEY AUTO_INCREMENT,
userid VARCHAR(30) NOT NULL
);
class User {
constructor() {
this.id
this.userid
}
}
User.find() // SELECT * FROM User;
예를 들어 위의 User class를 가지고 바로 위의 SQL 구문(CREATE 문)을 실행하려 하는 것이 "ORM"이다!!
Node.js - sequelize, typeORM(typeORM은 typescript 기반이라 지금 배우기는 이르다!!)
ORM을 배우면 향후 NoSQL을 배우기 쉬어짐!!
ORM을 설정하고 간단히 사용까지 할 예정!!
ORM을 통해 SQL 속성을 객체로 만들기 때문에 model 파일(models 디렉토리를 이미 구축해놓음!)을 새로 생성함!
sequelize를 가지고 ORM을 구현함!
model을 생성해서(객체를 만들어서) "Table"을 생성함!
User
- controller `postSignup`
- service `signup`
- repository `addUser`
back
server.js
// require("dotenv").config;
// --> require를 통해 dotenv 파일을 가져와서 config를 호출하면 ".env 파일"을 읽고 해당 파일에서 변수를 읽고 시스템 환경변수(process.env)에 해당 변수값을 잠깐 넣어놓음!
// --> 이렇게 되면 "const PORT = process.env.PORT || 3000;"의 경우, "process.env" 객체의 PORT 변수에 ".env 파일"에서 지정한 PORT 값인 3001이 할당됨!!
const express = require("express");
const app = express();
const config = require("./config");
const HttpException = config.exception.HttpException;
// const PORT = process.env.PORT || 3000;
const { sequelize } = require("./models");
const router = require("./routes");
app.use(router);
app.use((error, req, res, next) => {
// 응답 코드 500
// if (error instanceof Error) {}
console.error(error);
if (error instanceof HttpException) {
res.json({
isError: true,
message: error.message,
status: error.status,
});
} else if (error instanceof Error) {
res.json({
isError: true,
message: error.message,
});
}
});
app.listen(config.port, async () => {
await sequelize.sync({ force: true });
console.log(`server start ${config.port}`);
});
config.js
require("dotenv").config();
const HttpException = require("./exceptions/HTTPException");
const host = process.env.DB_HOST || "127.0.0.1";
const port = process.env.DB_PORT || 3306;
const user = process.env.DB_USER || "본인 user명";
const password = process.env.DB_PASSWORD || "본인 MySQL 비밀번호";
const database = process.env.DB_DATABASE || "comments";
const config = {
exception: {
HttpException,
},
env: process.env.NODE_ENV || "development",
port: process.env.PORT || 3000,
db: {
development: {
username: user,
password: password,
database: database,
port: port,
host: host,
dialect: "mysql",
},
test: {
username: user,
password: password,
database: database,
port: port,
host: host,
dialect: "mysql",
logging: false,
},
},
};
module.exports = config;
exceptions/HTTPException.js
class HttpException extends Error {
constructor(message) {
super(message);
this.status = 500;
}
}
// const e = new HTTPException("요청 데이터가 없음!!", 500);
// console.log(e);
// console.log(e.message, e.status);
// console.log(typeof e); // "e"는 인스턴스화 된 것이기에 타입은 객체(object)이다!!
module.exports = HttpException;
user/user.controller.js
class UserController {
constructor({ UserService }) {
this.UserService = UserService;
}
async postSignup(req, res, next) {
try {
const { userid, userpw, username } = req.body;
const response = await this.UserService.signup({
userid,
userpw,
username,
});
res.status(201).json(response);
} catch (e) {
next(e);
}
}
}
module.exports = UserController;
user/user.service.js
class UserService {
constructor({ UserRepository }) {
this.UserRepository = UserRepository;
}
async signup({ userid, userpw, username }) {
try {
const user = await this.UserRepository.addUser({
userid,
userpw,
username,
});
return user;
} catch (e) {
throw new Error(e);
}
}
}
module.exports = UserService;
user/user.repository.js
class UserRepository {
constructor({ User }) {
this.User = User;
}
async addUser(payload) {
try {
const user = await this.User.create(payload);
return user;
} catch (e) {
throw new Error(e);
}
}
async getUserByUserId({ userid }) {
const user = await this.User.findOne({
where: {
userid: userid,
},
});
return user.dataValues;
}
}
module.exports = UserRepository;
user/user.module.js
const {
sequelize: {
models: { User },
},
} = require("../models");
const UserRepository = require("./user.repository");
const repository = new UserRepository({ User });
repository.addUser({ userid: "qwer", userpw: "1234", username: "sangbeom" });
repository.getUserByUserId({ userid: "qwer" }).then((data) => {
console.log(data);
});
// console.log(repository);
models/index.js
const config = require("../config");
const Sequelize = require("sequelize");
const env = config.env; // development
const db = config.db[env];
const sequelize = new Sequelize(db.database, db.username, db.password, db); // model 객체가 들어감!!
// console.log(sequelize);
// const user = require("./user.model"); // function
// user(sequelize, Sequelize);
const user = require("./user.model")(sequelize, Sequelize);
// console.dir(user);
console.log(user);
console.log(sequelize.models.User === user);
module.exports = {
Sequelize,
sequelize,
};
// console.log(typeof Sequelize); // function("Sequelize"는 정확히는 class에 해당함!!)
// console.log(db, env);
// console.log(config);
models/user.model.js
// 모델을 만드는 방법
// 1) class --> 정적 메서드
// 2) 함수형(function) --> 아래 코드는 함수를 사용하여 모델을 만드는 방식이다!!
module.exports = (sequelize, DataTypes) => {
// "define" 함수는 모델을 생성해줌!!
// 첫번째 인자값: 객체의 속성명(object의 이름 정의)
// 두번째 인자값: Table field 정보
// 세번째 인자값: Table option 정보
return sequelize.define(
"User",
{
userid: {
type: DataTypes.STRING(30),
allowNull: false,
unique: true,
},
userpw: {
type: DataTypes.STRING(64),
allowNull: false,
},
username: {
type: DataTypes.STRING(30),
allowNull: false,
},
gender: {
type: DataTypes.STRING(2),
defaultValue: "여자",
},
},
{
freezeTableName: true,
// timestamps: false,
}
);
};
.env
PORT=3001
NODE_ENV=development
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=본인 user명
DB_PASSWORD=본인 MySQL 비밀번호
DB_DATABASE=comments