MongoDB와 Express.js로 블로그 만들기 – 완성까지 한번에!

프로젝트 소개 및 목표

MongoDB와 Express.js로 블로그 만들기 프로젝트는 백엔드 개발의 핵심 기술을 실전에서 익힐 수 있는 최고의 실습 과제입니다. 이 가이드를 통해 RESTful API 설계, 데이터베이스 모델링, 사용자 인증, CRUD 작업 등 실무에서 필요한 모든 기능을 구현할 수 있습니다. 완성된 블로그 시스템은 게시글 작성, 수정, 삭제, 조회 기능과 함께 사용자 인증, 댓글 시스템, 카테고리 분류 등을 포함합니다. 이 프로젝트는 포트폴리오로도 활용할 수 있으며, Full-stack 개발자로 성장하기 위한 탄탄한 기반이 됩니다.

필요한 기술 스택

이 프로젝트를 완성하기 위해 필요한 핵심 기술은 다음과 같습니다. Node.js는 서버 환경을 제공하며, Express.js는 라우팅과 미들웨어 관리를 담당합니다. MongoDB는 NoSQL 데이터베이스로 유연한 스키마 설계가 가능하고, Mongoose를 통해 객체 모델링을 수행합니다. 추가로 JWT를 사용한 인증, bcrypt로 비밀번호 암호화, Joiexpress-validator로 입력 검증을 구현합니다. 프론트엔드는 EJS 템플릿 엔진이나 React를 선택할 수 있습니다.

프로젝트 셋업

먼저 개발 환경을 구성합니다. Node.js와 MongoDB가 설치되어 있어야 하며, MongoDB Atlas를 사용하면 클라우드 데이터베이스를 무료로 이용할 수 있습니다.

// 프로젝트 초기화
mkdir blog-project
cd blog-project
npm init -y

// 필수 패키지 설치
npm install express mongoose dotenv cors
npm install bcryptjs jsonwebtoken express-validator
npm install --save-dev nodemon

// package.json 스크립트 추가
"scripts": {
  "start": "node server.js",
  "dev": "nodemon server.js"
}

프로젝트 구조는 MVC 패턴을 따르며, models, routes, controllers, middleware 폴더로 구성합니다. .env 파일에 환경 변수를 설정하여 데이터베이스 연결 정보와 JWT 시크릿을 안전하게 관리합니다.

단계별 구현 과정

1단계: 서버 및 데이터베이스 연결

MongoDB와 Express.js로 블로그 만들기의 첫 단계는 서버와 데이터베이스 연결입니다.

// 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.MONGODB_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => console.log('MongoDB 연결 성공'))
.catch(err => console.error('MongoDB 연결 실패:', err));

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log(`서버가 포트 ${PORT}에서 실행중입니다`);
});

2단계: 데이터 모델 설계

사용자, 게시글, 댓글 모델을 Mongoose 스키마로 정의합니다.

// models/User.js
const mongoose = require('mongoose');

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 });

module.exports = mongoose.model('User', userSchema);

// models/Post.js
const postSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
    trim: true
  },
  content: {
    type: String,
    required: true
  },
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  category: {
    type: String,
    required: true
  },
  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 bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

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 hashedPassword = await bcrypt.hash(password, 12);
    
    // 새 사용자 생성
    const user = new User({
      username,
      email,
      password: hashedPassword
    });
    
    await user.save();
    
    // JWT 토큰 생성
    const token = jwt.sign(
      { userId: user._id, email: user.email },
      process.env.JWT_SECRET,
      { expiresIn: '7d' }
    );
    
    res.status(201).json({
      message: '회원가입 성공',
      token,
      userId: user._id
    });
  } 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) {
      return res.status(401).json({ message: '인증 실패' });
    }
    
    const isValidPassword = await bcrypt.compare(password, user.password);
    if (!isValidPassword) {
      return res.status(401).json({ message: '인증 실패' });
    }
    
    const token = jwt.sign(
      { userId: user._id, email: user.email },
      process.env.JWT_SECRET,
      { expiresIn: '7d' }
    );
    
    res.json({ token, userId: user._id });
  } catch (error) {
    res.status(500).json({ message: '서버 오류', error: error.message });
  }
};

4단계: 게시글 CRUD API 구현

블로그의 핵심 기능인 게시글 관리 API를 작성합니다.

// controllers/postController.js
const Post = require('../models/Post');

// 게시글 생성
exports.createPost = async (req, res) => {
  try {
    const { title, content, category, tags } = req.body;
    
    const post = new Post({
      title,
      content,
      category,
      tags,
      author: req.userId // 미들웨어에서 추출한 사용자 ID
    });
    
    await post.save();
    res.status(201).json({ message: '게시글 생성 성공', post });
  } catch (error) {
    res.status(500).json({ message: '서버 오류', error: error.message });
  }
};

// 게시글 목록 조회 (페이지네이션)
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 email')
      .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.getPost = async (req, res) => {
  try {
    const post = await Post.findById(req.params.id)
      .populate('author', 'username email');
    
    if (!post) {
      return res.status(404).json({ message: '게시글을 찾을 수 없습니다' });
    }
    
    // 조회수 증가
    post.views += 1;
    await post.save();
    
    res.json(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.userId) {
      return res.status(403).json({ message: '권한이 없습니다' });
    }
    
    const { title, content, category, tags } = req.body;
    post.title = title || post.title;
    post.content = content || post.content;
    post.category = category || post.category;
    post.tags = tags || post.tags;
    
    await post.save();
    res.json({ message: '게시글 수정 성공', post });
  } 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.userId) {
      return res.status(403).json({ message: '권한이 없습니다' });
    }
    
    await post.deleteOne();
    res.json({ message: '게시글 삭제 성공' });
  } catch (error) {
    res.status(500).json({ message: '서버 오류', error: error.message });
  }
};

5단계: 인증 미들웨어 및 라우팅

MongoDB와 Express.js로 블로그 만들기 프로젝트에서 보안은 필수입니다.

// middleware/auth.js
const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {
  try {
    const token = req.headers.authorization?.split(' ')[1];
    
    if (!token) {
      return res.status(401).json({ message: '인증 토큰이 없습니다' });
    }
    
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.userId = decoded.userId;
    next();
  } catch (error) {
    res.status(401).json({ message: '유효하지 않은 토큰입니다' });
  }
};

// routes/posts.js
const express = require('express');
const router = express.Router();
const postController = require('../controllers/postController');
const auth = require('../middleware/auth');

router.get('/', postController.getPosts);
router.get('/:id', postController.getPost);
router.post('/', auth, postController.createPost);
router.put('/:id', auth, postController.updatePost);
router.delete('/:id', auth, postController.deletePost);

module.exports = router;

// server.js에 라우트 추가
const authRoutes = require('./routes/auth');
const postRoutes = require('./routes/posts');

app.use('/api/auth', authRoutes);
app.use('/api/posts', postRoutes);

테스트 및 배포

API 테스트는 Postman이나 Thunder Client를 사용합니다. 회원가입 후 로그인하여 받은 JWT 토큰을 Authorization 헤더에 포함시켜 게시글 작성, 수정, 삭제를 테스트합니다. 배포는 Heroku, Railway, Render 등의 플랫폼을 활용할 수 있습니다.

// 환경 변수 설정 (.env)
MONGODB_URI=mongodb+srv://username:[email protected]/blog
JWT_SECRET=your_super_secret_key_here
PORT=5000
NODE_ENV=production

프로덕션 환경에서는 HTTPS 사용, CORS 설정 강화, rate limiting, helmet.js로 보안 헤더 설정, express-mongo-sanitize로 NoSQL 인젝션 방지 등 추가 보안 조치가 필요합니다. PM2를 사용하면 프로세스 관리와 무중단 배포가 가능합니다. MongoDB Atlas의 인덱스 설정으로 쿼리 성능을 최적화하고, Redis 캐싱을 적용하면 응답 속도를 크게 향상시킬 수 있습니다.

마무리 및 확장 아이디어

이제 MongoDB와 Express.js로 블로그 만들기 프로젝트의 핵심 기능이 완성되었습니다. 여기서 더 나아가 댓글 시스템, 좋아요 기능, 이미지 업로드(Multer + Cloudinary), 검색 기능(텍스트 인덱스), 마크다운 에디터, 소셜 로그인(Passport.js), 이메일 인증, 관리자 대시보드 등을 추가할 수 있습니다. 프론트엔드는 React나 Vue.js로 SPA를 구축하거나 Next.js로 SEO 최적화된 블로그를 만들 수 있습니다. GraphQL API로 전환하거나 마이크로서비스 아키텍처로 확장하는 것도 좋은 학습 경험이 됩니다. 이 프로젝트를 GitHub에 공개하고 상세한 README를 작성하면 훌륭한 포트폴리오가 됩니다!

📚 함께 읽으면 좋은 글

1

MongoDB와 Express.js로 블로그 만들기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 20.
🎯 MongoDB와 Express.js로 블로그 만들기

2

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 22.
🎯 React + Node.js 풀스택 앱 배포하기

3

실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 21.
🎯 실시간 채팅 앱 만들기 with Socket.io

4

React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 20.
🎯 React + Node.js 풀스택 앱 배포하기

5

REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!

📂 프로젝트 아이디어
📅 2025. 11. 18.
🎯 REST API 서버 구축 단계별 튜토리얼

💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!

📢 이 글이 도움되셨나요? 공유해주세요!

여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨

🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏

💬 여러분의 소중한 의견을 들려주세요!

여러분은 MongoDB와 Express.js로 블로그 만들기에 대해 어떻게 생각하시나요?

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨

🔔 블로그 구독하고 최신 글을 받아보세요!

📚
다양한 주제
17개 카테고리

정기 업데이트
하루 3회 발행

🎯
실용적 정보
바로 적용 가능

💡
최신 트렌드
2025년 기준

🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨

📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!

답글 남기기