MongoDB와 Express.js로 블로그 만들기 – 완성까지 한번에!
프로젝트 소개 및 목표
🔗 관련 에러 해결 가이드
MongoDB와 Express.js로 블로그 만들기 프로젝트는 백엔드 개발의 핵심 개념을 실습할 수 있는 최고의 포트폴리오 프로젝트입니다. 이 가이드에서는 RESTful API 설계, NoSQL 데이터베이스 연동, 인증/인가 시스템 구현까지 실무에서 필요한 모든 기술을 단계별로 배웁니다. 완성된 블로그는 게시글 CRUD, 댓글 시스템, 사용자 인증 기능을 포함하며, 실제 서비스 가능한 수준의 애플리케이션이 됩니다. 이 프로젝트를 통해 Node.js 생태계의 핵심 기술을 마스터하고, 취업이나 사이드 프로젝트에 바로 활용할 수 있는 실력을 갖추게 됩니다.
필요한 기술 스택
이 프로젝트를 진행하기 위해 필요한 기술 스택은 다음과 같습니다:
- Node.js & Express.js: 서버 프레임워크 및 라우팅
- MongoDB & Mongoose: NoSQL 데이터베이스 및 ODM
- JWT (jsonwebtoken): 사용자 인증/인가
- bcrypt: 비밀번호 암호화
- dotenv: 환경변수 관리
- express-validator: 입력값 검증
- Postman: API 테스트 도구
프로젝트 셋업
먼저 프로젝트 디렉토리를 생성하고 필요한 패키지를 설치합니다. MongoDB는 MongoDB Atlas를 사용하여 클라우드 데이터베이스를 구성하거나 로컬에 설치할 수 있습니다.
// 1. 프로젝트 초기화
mkdir blog-backend && cd blog-backend
npm init -y
// 2. 필요한 패키지 설치
npm install express mongoose dotenv bcryptjs jsonwebtoken cors
npm install --save-dev nodemon
// 3. 프로젝트 구조 생성
mkdir models routes controllers middleware config
touch server.js .env
.env 파일에 환경변수를 설정합니다:
PORT=5000
MONGO_URI=mongodb+srv://username:[email protected]/blog
JWT_SECRET=your_secret_key_here
NODE_ENV=development
단계별 구현 과정
1단계: 서버 및 데이터베이스 연결 설정
Express 서버를 설정하고 MongoDB에 연결합니다.
// server.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();
const app = express();
// 미들웨어
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// MongoDB 연결
mongoose.connect(process.env.MONGO_URI)
.then(() => console.log('MongoDB 연결 성공'))
.catch(err => console.error('MongoDB 연결 실패:', err));
// 라우트
app.use('/api/auth', require('./routes/auth'));
app.use('/api/posts', require('./routes/posts'));
app.use('/api/comments', require('./routes/comments'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`서버 실행 중: ${PORT}`));
2단계: Mongoose 스키마 및 모델 정의
사용자, 게시글, 댓글 모델을 정의합니다.
// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
password: {
type: String,
required: true,
minlength: 6
},
role: {
type: String,
enum: ['user', 'admin'],
default: 'user'
}
}, { timestamps: true });
// 비밀번호 해싱
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 12);
next();
});
// 비밀번호 검증 메서드
userSchema.methods.comparePassword = async function(candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
module.exports = mongoose.model('User', userSchema);
// models/Post.js
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
trim: true,
maxlength: 200
},
content: {
type: String,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
category: {
type: String,
enum: ['기술', '일상', '프로젝트', '튜토리얼'],
default: '일상'
},
tags: [String],
views: {
type: Number,
default: 0
},
published: {
type: Boolean,
default: false
}
}, { timestamps: true });
module.exports = mongoose.model('Post', postSchema);
3단계: 인증 시스템 구현
회원가입, 로그인, JWT 토큰 발급을 구현합니다.
// controllers/authController.js
const User = require('../models/User');
const jwt = require('jsonwebtoken');
// JWT 토큰 생성
const generateToken = (userId) => {
return jwt.sign({ id: userId }, process.env.JWT_SECRET, {
expiresIn: '7d'
});
};
// 회원가입
exports.register = async (req, res) => {
try {
const { username, email, password } = req.body;
// 중복 체크
const existingUser = await User.findOne({ $or: [{ email }, { username }] });
if (existingUser) {
return res.status(400).json({ message: '이미 존재하는 사용자입니다.' });
}
// 사용자 생성
const user = await User.create({ username, email, password });
const token = generateToken(user._id);
res.status(201).json({
message: '회원가입 성공',
token,
user: {
id: user._id,
username: user.username,
email: user.email
}
});
} catch (error) {
res.status(500).json({ message: '서버 오류', error: error.message });
}
};
// 로그인
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user || !(await user.comparePassword(password))) {
return res.status(401).json({ message: '이메일 또는 비밀번호가 잘못되었습니다.' });
}
const token = generateToken(user._id);
res.json({
message: '로그인 성공',
token,
user: {
id: user._id,
username: user.username,
email: user.email
}
});
} catch (error) {
res.status(500).json({ message: '서버 오류', error: error.message });
}
};
4단계: 게시글 CRUD API 구현
MongoDB와 Express.js로 블로그 만들기의 핵심인 게시글 관리 기능을 구현합니다.
// controllers/postController.js
const Post = require('../models/Post');
// 게시글 목록 조회 (페이지네이션)
exports.getPosts = async (req, res) => {
try {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const skip = (page - 1) * limit;
const posts = await Post.find({ published: true })
.populate('author', 'username')
.sort({ createdAt: -1 })
.skip(skip)
.limit(limit);
const total = await Post.countDocuments({ published: true });
res.json({
posts,
currentPage: page,
totalPages: Math.ceil(total / limit),
totalPosts: total
});
} catch (error) {
res.status(500).json({ message: '서버 오류', error: error.message });
}
};
// 게시글 생성
exports.createPost = async (req, res) => {
try {
const { title, content, category, tags, published } = req.body;
const post = await Post.create({
title,
content,
category,
tags,
published,
author: req.user.id
});
res.status(201).json({ message: '게시글 작성 성공', post });
} catch (error) {
res.status(500).json({ message: '서버 오류', error: error.message });
}
};
// 게시글 수정
exports.updatePost = async (req, res) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ message: '게시글을 찾을 수 없습니다.' });
}
if (post.author.toString() !== req.user.id) {
return res.status(403).json({ message: '권한이 없습니다.' });
}
const updatedPost = await Post.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true }
);
res.json({ message: '수정 완료', post: updatedPost });
} catch (error) {
res.status(500).json({ message: '서버 오류', error: error.message });
}
};
// 게시글 삭제
exports.deletePost = async (req, res) => {
try {
const post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ message: '게시글을 찾을 수 없습니다.' });
}
if (post.author.toString() !== req.user.id) {
return res.status(403).json({ message: '권한이 없습니다.' });
}
await post.deleteOne();
res.json({ message: '게시글 삭제 완료' });
} catch (error) {
res.status(500).json({ message: '서버 오류', error: error.message });
}
};
5단계: 인증 미들웨어 구현
JWT 토큰을 검증하여 보호된 라우트에 접근을 제어합니다.
// middleware/auth.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');
exports.protect = async (req, res, next) => {
try {
let token;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
token = req.headers.authorization.split(' ')[1];
}
if (!token) {
return res.status(401).json({ message: '인증 토큰이 없습니다.' });
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.id).select('-password');
if (!req.user) {
return res.status(401).json({ message: '사용자를 찾을 수 없습니다.' });
}
next();
} catch (error) {
res.status(401).json({ message: '유효하지 않은 토큰입니다.' });
}
};
6단계: 라우트 설정
API 엔드포인트를 정의하고 컨트롤러와 연결합니다.
// routes/posts.js
const express = require('express');
const router = express.Router();
const { protect } = require('../middleware/auth');
const {
getPosts,
getPost,
createPost,
updatePost,
deletePost
} = require('../controllers/postController');
router.get('/', getPosts);
router.get('/:id', getPost);
router.post('/', protect, createPost);
router.put('/:id', protect, updatePost);
router.delete('/:id', protect, deletePost);
module.exports = router;
테스트 및 배포
API 테스트
Postman이나 Thunder Client를 사용하여 각 엔드포인트를 테스트합니다:
// 회원가입 테스트
POST http://localhost:5000/api/auth/register
Content-Type: application/json
{
"username": "testuser",
"email": "[email protected]",
"password": "password123"
}
// 게시글 작성 테스트
POST http://localhost:5000/api/posts
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"title": "첫 번째 게시글",
"content": "안녕하세요! 블로그 첫 글입니다.",
"category": "일상",
"tags": ["인사", "첫글"],
"published": true
}
배포 준비
Heroku, Railway, 또는 Vercel에 배포할 수 있습니다. package.json에 시작 스크립트를 추가합니다:
// package.json
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
}
환경변수를 배포 플랫폼에 설정하고, MongoDB Atlas 연결 문자열을 확인합니다. CORS 설정도 프로덕션 도메인에 맞게 조정합니다.
마무리 및 확장 아이디어
이제 MongoDB와 Express.js로 블로그 만들기 프로젝트의 기본 구조가 완성되었습니다. 추가로 구현할 수 있는 기능들:
- 댓글 시스템: 게시글에 댓글 및 대댓글 기능 추가
- 이미지 업로드: Multer와 Cloudinary를 사용한 파일 업로드
- 검색 기능: 제목, 내용, 태그 기반 검색 구현
- 좋아요/북마크: 사용자 인터랙션 기능 추가
- 관리자 대시보드: 통계 및 관리 기능
- 이메일 인증: Nodemailer를 활용한 회원가입 인증
이 프로젝트를 GitHub에 올리고 README를 작성하여 포트폴리오로 활용하세요!
📚 함께 읽으면 좋은 글
React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!
📅 2025. 10. 2.
🎯 React + Node.js 풀스택 앱 배포하기
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 10. 1.
🎯 REST API 서버 구축 단계별 튜토리얼
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 10. 1.
🎯 실시간 채팅 앱 만들기 with Socket.io
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 10. 1.
🎯 REST API 서버 구축 단계별 튜토리얼
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 10. 1.
🎯 REST API 서버 구축 단계별 튜토리얼
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글을 읽고 새롭게 알게 된 정보가 있다면 공유해주세요!
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!