728x90
React로 프론트엔드를 설계하고, Express.js서버로 간단한 CRUD 기능이 있는 커뮤니티를 제작하고 있다.
client와 server의 폴더를 완전히 분리시켜서 작업하였고, concurrently와 nodemon을 이용하여 개발을 하였다.
Backend의 Architecture는 이렇다.
MYUN_SJ backend/
├── app.js
├── package.json
├── /config
│ └── db.js
├── /models
│ ├── user.js
│ └── post.js
├── /routes
│ ├── index.js
│ ├── users.js
│ └── posts.js
├── /controllers
│ ├── usersController.js
│ └── postsController.js
├── /middlewares
│ └── authMiddleware.js
├── /public
│ ├── /images
│ ├── /javascripts
│ └── /stylesheets
└── /views (RESTful API이기 때문에 제거)
지금은 개발단계이기 때문에 localhost로 진행하였고, public이나 index.js의 활용은 아직 하고있지 않는다.
완전히 분리하여 포트번호도 다르기 때문에, cors정책을 위반하게 된다. 이를 처리하는 로직을 express 서버의 main 호출단계에 추가해주었다. main단에서는 최대한 호출정도의 기능만 하기 위하여 최대한 압축시켰다.
const express = require('express');
const app = express();
const cors = require('cors');
const session = require('express-session');
require('dotenv').config();
const sequelize = require('./config/db');
const User = require('./models/user');
const Post = require('./models/post');
const postsRoutes = require('./routes/posts');
const usersRoutes = require('./routes/users');
app.use(cors());
app.use((req, res, next) => {
res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
res.header('Pragma', 'no-cache');
res.header('Expires', '0');
next();
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(session({
secret: process.env.SESSION_KEY,
resave: false,
saveUninitialized: true,
cookie: { secure: 'auto' }
}));
app.use('/api/posts', postsRoutes);
app.use('/api/users', usersRoutes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
sequelize.authenticate().then(() => {
console.log('Database connected...');
sequelize.sync().then(() => {
console.log('Tables created...');
}).catch(err => console.log('Error: ' + err));
}).catch(err => console.log('Error: ' + err));
});
DB는 MySQL의 sequelize를 사용하여 편하게 설계하였다. GMT 시간을 맞추는 로직이 필요하였다.
require('dotenv').config();
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
host: process.env.DB_HOST,
dialect: 'mysql',
timezone: '+09:00'
});
sequelize.authenticate()
.then(() => console.log('Connection has been established successfully.'))
.catch(err => console.error('Unable to connect to the database:', err));
module.exports = sequelize;
프론트에서 최대한 요청을 하고, 백에서 최대한 처리를 하기 위하여 로그아웃 로직도 백에 추가시켜주었다. Node.js이기 때문에 적합한 Rest.API를 채택하여 통신을 하였다.
const User = require('../models/user');
const usersController = {
// 모든 사용자 조회
getAllUsers: async (req, res) => {
try {
const users = await User.findAll();
res.json(users);
} catch (error) {
res.status(500).json({ message: error.message });
}
},
// 사용자 생성
createUser: async (req, res) => {
try {
const user = await User.create(req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ message: error.message });
}
},
// 특정 사용자 조회
getUserById: async (req, res) => {
try {
const user = await User.findByPk(req.params.id);
if (user) {
res.json(user);
} else {
res.status(404).json({ message: '사용자를 찾을 수 없습니다.' });
}
} catch (error) {
res.status(500).json({ message: error.message });
}
},
// 사용자 업데이트
updateUser: async (req, res) => {
try {
const user = await User.findByPk(req.params.id);
if (user) {
await user.update(req.body);
res.json(user);
} else {
res.status(404).json({ message: '사용자를 찾을 수 없습니다.' });
}
} catch (error) {
res.status(400).json({ message: error.message });
}
},
// 사용자 삭제
deleteUser: async (req, res) => {
try {
const user = await User.findByPk(req.params.id);
if (user) {
await user.destroy();
res.status(204).send();
} else {
res.status(404).json({ message: '사용자를 찾을 수 없습니다.' });
}
} catch (error) {
res.status(500).json({ message: error.message });
}
},
// 사용자 로그인
loginUser: async (req, res) => {
const { email, pw } = req.body;
try {
const user = await User.findOne({ where: { email: email } });
if (!user) {
return res.status(404).json({ message: '사용자를 찾을 수 없습니다.' });
}
// 비밀번호 검증 로직 추가 일치 여부만 확인
if (user.pw !== pw) {
return res.status(400).json({ message: '잘못된 비밀번호입니다.' });
}
// 세션에 사용자 ID 저장
req.session.userId = user.id;
res.json({ message: '로그인 성공!' });
} catch (error) {
res.status(500).json({ message: error.message });
}
},
// 사용자 로그아웃
logoutUser: async (req, res) => {
try {
req.session.destroy((err) => {
if (err) {
console.log(err);
res.status(500).json({ message: '로그아웃 에러' });
} else {
res.json({ message: '로그아웃 성공' });
}
});
} catch (error) {
res.status(500).json({ message: error.message });
}
}
};
module.exports = usersController;
세션 방식을 이용하여 통신했기 때문에 bcrypt 등(아직 추가하지 않음) 여러 검증 로직이 필요했었다.
function authMiddleware(req, res, next) {
if (req.session && req.session.userId) {
next(); // 세션 정보가 유효하면 다음 미들웨어로 진행
} else {
res.status(401).send('Unauthorized'); // 로그인되지 않은 사용자에게 401 상태 코드 응답
}
}
module.exports = authMiddleware;
https://github.com/MYun-SJ/MYun_SJ/tree/main/server
728x90
'서버' 카테고리의 다른 글
Proxy 서버 구현 (1) | 2024.03.24 |
---|---|
echo server, tiny server 구현 (2) | 2024.03.24 |
Socket, Redirection, Pipe (1) | 2024.03.23 |
Parsing, Caching, Filtering, Load Balancing, MTU, NAT (1) | 2024.03.23 |