코드의 구조를 체계적으로 구조적으로 구현하는 것
코드의 역할을 독립적으로 분리
단방향 의존성 (각 layer들을 require)
파일1 HTTP Request/Respone 처리
파일2 Business Logic 처리
파일3 Database 통신 처리
Client
Presentation Layer
Controller
Business Layer
Service
Persistence Layer
Model
Database
유저 회원 가입 및 로그인 부분
app.js
:Express 서버 설치 및 미들웨어 세팅
require('dotenv').config();
const http = require("http");
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const route = require("./routes");
app = express()
const server = http.createServer(app);
const PORT = process.env.PORT;
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
app.use(route);
const start = async () => {
server.listen(PORT, () => console.log(`server is listening on ${PORT}`))
}
start()
routes/index.js
: express 불러오기, router 모듈 export, 각 route 대분기
const express = require('express');
const router = express.Router();
const userRouter = require("./userRouter")
const postRouter = require("./postRouter")
const likeRouter = require("./likeRouter")
router.use('/users', userRouter);
router.use('/posts', postRouter);
router.use('/likes', likeRouter);
module.exports = router;
routes/userRouter.js
: user uri 소분기, method 설정, 단방향 require 설정, router 모듈 export
const express = require('express');
const { userController } = require('../controllers');
const router = express.Router();
router.post('/signup', userController.signUp);
router.post('/signin', userController.signIn);
module.exports = router;
index.js
: 기능별 contorller 분기
const userController = require('./userController');
const postController = require('./postController');
const likeController = require('./likeController');
module.exports = {
userController,
postController,
likeController,
}
userController.js
: Presentation layer, 기능별(회원가입, 로그인) 입력값 출력값 설정, controller 모듈 Export, userService Import
const { userService } = require('../services')
const signUp = async (req, res) => {
const { name, email, profileImage, password } = req.body;
const user = await userService.signUp(name, email, profileImage, password);
return res.status(201).json({ result : user });
};
const signIn = async (req, res) => {
const { email, password } = req.body;
const accessToken = await userService.signIn(email, password)
return res.status(200).json({ token : accessToken})
}
module.exports = {
signUp,
signIn,
}
index.js
: 기능별 serivce 모듈 export
const userService = require('./userService');
const postService = require('./postService')
const likeService = require('./likeService')
module.exports = {
userService,
postService,
likeService,
}
userService
: Business Layer, 회원가입 및 로그인 bcyrpt 해시값 설정 및 jwt 발급 로직 추가
const { userDao } = require('../models/');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const signUp = async (name, email, profileImage, password) => {
const saltRounds = 10;
const makeHash = async (password, saltRounds) => {
return await bcrypt.hash(password, saltRounds);
};
hashedPassword = await makeHash(password, saltRounds);
return await userDao.postUser(name, email, profileImage, hashedPassword);
};
const signIn = async (email, password) => {
const user= await userDao.verifyUser(email);
const checkHash = await bcrypt.compare(password, user.password)
if(!checkHash) {
const err = new Error("invalid password");
err.statusCode = 400;
throw err;
}
return jwt.sign({ sub: user.id, email: user.email }, process.env.SECRETKEY);
};
module.exports = {
signUp,
signIn,
}
index.js
: DAO 모듈 분기
const userDao = require('./userDao');
const postDao = require('./postDao')
const likeDao = require('./likeDao')
module.exports = {
userDao,
postDao,
likeDao,
}
userDao.js
: Persistence Layer, MySQL 쿼리문, DB 관리 Layer
const database = require('./DataSource')
//return id 필수
const postUser = async (name, email, profileImage, password) => {
const user = await database.query(
`INSERT INTO users(
name,
email,
profile_image,
password
) VALUES (?, ?, ?, ?);
`,
[name, email, profileImage, password]
);
return user;
};
const verifyUser = async (email, password) => {
const [userEncryption] = await database.query(
`SELECT
id,
email,
password
FROM users
WHERE email = ?
`,
[email]
);
return userEncryption;
}
module.exports = {
postUser,
verifyUser,
}
DataSourc.js
:typeORM 모듈 import 및 각 Dao Layer를 위한 typoORM 객체 export
const { DataSource } =require('typeorm');
const database = new DataSource({
type: process.env.TYPEORM_CONNECTION,
host: process.env.TYPEORM_HOST,
port: process.env.TYPEORM_PORT,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE
})
database.initialize()
.then(() => {
console.log("Data Source has been initialized!")
})
.catch((err) => {
console.error("Error during Data Source initialization", err)
})
module.exports = database;
app.js 서버 세팅 -> routes 분기 -> controllers(Presentation Layer) -> services(Business Layer) -> models(Persistence Layer) -> Database 순으로 단방향성을 보여준다.