REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
1. 프로젝트 소개 및 목표
🔗 관련 에러 해결 가이드
이번 REST API 서버 구축 단계별 튜토리얼에서는 Node.js와 Express를 활용하여 실무에서 바로 사용할 수 있는 RESTful API 서버를 처음부터 끝까지 구축해보겠습니다. 이 튜토리얼을 통해 기본적인 CRUD 작업부터 인증, 에러 핸들링, 데이터베이스 연동까지 모든 과정을 단계별로 학습할 수 있습니다. 완성된 프로젝트는 포트폴리오로 활용하거나 실제 서비스의 백엔드 기반으로 사용할 수 있으며, 현대적인 웹 개발의 핵심 개념을 이해하는 데 큰 도움이 될 것입니다. 초보자도 따라할 수 있도록 모든 단계를 상세히 설명하며, 실무 팁과 베스트 프랙티스도 함께 제공합니다.
2. 필요한 기술 스택
이 REST API 서버 구축 단계별 튜토리얼을 진행하기 위해 다음 기술들이 필요합니다:
- Node.js (v16 이상): 서버 사이드 JavaScript 런타임
- Express.js: 빠르고 간결한 웹 프레임워크
- MongoDB: NoSQL 데이터베이스 (또는 PostgreSQL)
- Mongoose: MongoDB ODM 라이브러리
- JWT: 토큰 기반 인증
- dotenv: 환경 변수 관리
- Postman 또는 Thunder Client: API 테스트 도구
기본적인 JavaScript 지식과 HTTP 프로토콜에 대한 이해가 있다면 더욱 좋습니다.
3. 프로젝트 셋업
프로젝트를 시작하기 위한 초기 설정을 진행합니다. 먼저 새로운 프로젝트 디렉토리를 생성하고 npm을 초기화합니다.
# 프로젝트 디렉토리 생성
mkdir rest-api-tutorial
cd rest-api-tutorial
# npm 초기화
npm init -y
# 필요한 패키지 설치
npm install express mongoose dotenv bcryptjs jsonwebtoken
npm install --save-dev nodemon
프로젝트 구조를 다음과 같이 구성합니다:
rest-api-tutorial/
├── src/
│ ├── controllers/
│ ├── models/
│ ├── routes/
│ ├── middleware/
│ └── config/
├── .env
├── .gitignore
├── server.js
└── package.json
.env 파일을 생성하여 환경 변수를 설정합니다:
PORT=3000
MONGODB_URI=mongodb://localhost:27017/rest-api-tutorial
JWT_SECRET=your_jwt_secret_key_here
package.json에 스크립트를 추가합니다:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
4. 단계별 구현 과정
4.1 기본 서버 설정
먼저 server.js 파일에 기본적인 Express 서버를 구성합니다.
// server.js
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
// 환경 변수 로드
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
// 미들웨어 설정
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));
// 기본 라우트
app.get('/', (req, res) => {
res.json({ message: 'REST API 서버가 실행 중입니다!' });
});
// 서버 시작
app.listen(PORT, () => {
console.log(`서버가 포트 ${PORT}에서 실행 중입니다.`);
});
4.2 데이터 모델 생성
사용자(User) 모델을 생성하여 데이터베이스 스키마를 정의합니다.
// src/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, '사용자명은 최소 3자 이상이어야 합니다']
},
email: {
type: String,
required: [true, '이메일은 필수입니다'],
unique: true,
lowercase: true,
match: [/^\S+@\S+\.\S+$/, '유효한 이메일 주소를 입력하세요']
},
password: {
type: String,
required: [true, '비밀번호는 필수입니다'],
minlength: [6, '비밀번호는 최소 6자 이상이어야 합니다']
},
createdAt: {
type: Date,
default: Date.now
}
});
// 비밀번호 암호화 미들웨어
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
try {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
} catch (error) {
next(error);
}
});
// 비밀번호 검증 메서드
userSchema.methods.comparePassword = async function(candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};
module.exports = mongoose.model('User', userSchema);
4.3 컨트롤러 구현
비즈니스 로직을 처리하는 컨트롤러를 작성합니다.
// src/controllers/userController.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({
success: false,
message: '이미 존재하는 사용자입니다'
});
}
// 새 사용자 생성
const user = await User.create({ username, email, password });
// 토큰 생성
const token = generateToken(user._id);
res.status(201).json({
success: true,
message: '회원가입 성공',
data: {
user: {
id: user._id,
username: user.username,
email: user.email
},
token
}
});
} catch (error) {
res.status(500).json({
success: false,
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({
success: false,
message: '이메일 또는 비밀번호가 올바르지 않습니다'
});
}
// 비밀번호 확인
const isPasswordValid = await user.comparePassword(password);
if (!isPasswordValid) {
return res.status(401).json({
success: false,
message: '이메일 또는 비밀번호가 올바르지 않습니다'
});
}
// 토큰 생성
const token = generateToken(user._id);
res.json({
success: true,
message: '로그인 성공',
data: {
user: {
id: user._id,
username: user.username,
email: user.email
},
token
}
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다',
error: error.message
});
}
};
// 사용자 프로필 조회
exports.getProfile = async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
if (!user) {
return res.status(404).json({
success: false,
message: '사용자를 찾을 수 없습니다'
});
}
res.json({
success: true,
data: { user }
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다',
error: error.message
});
}
};
// 모든 사용자 조회
exports.getAllUsers = async (req, res) => {
try {
const users = await User.find().select('-password');
res.json({
success: true,
count: users.length,
data: { users }
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다',
error: error.message
});
}
};
4.4 인증 미들웨어 구현
JWT 토큰을 검증하는 인증 미들웨어를 작성합니다.
// src/middleware/auth.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const auth = async (req, res, next) => {
try {
// 헤더에서 토큰 추출
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({
success: false,
message: '인증 토큰이 필요합니다'
});
}
// 토큰 검증
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// 사용자 확인
const user = await User.findById(decoded.id);
if (!user) {
return res.status(401).json({
success: false,
message: '유효하지 않은 토큰입니다'
});
}
// 요청 객체에 사용자 정보 추가
req.user = user;
next();
} catch (error) {
res.status(401).json({
success: false,
message: '인증에 실패했습니다',
error: error.message
});
}
};
module.exports = auth;
4.5 라우트 설정
API 엔드포인트를 정의하는 라우트를 구성합니다.
// src/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const auth = require('../middleware/auth');
// 공개 라우트
router.post('/register', userController.register);
router.post('/login', userController.login);
// 보호된 라우트 (인증 필요)
router.get('/profile', auth, userController.getProfile);
router.get('/users', auth, userController.getAllUsers);
module.exports = router;
server.js에 라우트를 연결합니다:
// server.js에 추가
const userRoutes = require('./src/routes/userRoutes');
// 라우트 설정
app.use('/api/auth', userRoutes);
// 404 에러 핸들링
app.use((req, res) => {
res.status(404).json({
success: false,
message: '요청한 리소스를 찾을 수 없습니다'
});
});
// 전역 에러 핸들링
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
success: false,
message: '서버 내부 오류가 발생했습니다',
error: process.env.NODE_ENV === 'development' ? err.message : undefined
});
});
5. 테스트 및 배포
5.1 API 테스트
Postman이나 Thunder Client를 사용하여 API를 테스트합니다.
회원가입 테스트:
POST http://localhost:3000/api/auth/register
Content-Type: application/json
{
"username": "testuser",
"email": "[email protected]",
"password": "password123"
}
로그인 테스트:
POST http://localhost:3000/api/auth/login
Content-Type: application/json
{
"email": "[email protected]",
"password": "password123"
}
프로필 조회 테스트:
GET http://localhost:3000/api/auth/profile
Authorization: Bearer YOUR_JWT_TOKEN
5.2 배포 준비
프로덕션 환경을 위한 설정을 추가합니다.
// src/config/database.js
const mongoose = require('mongoose');
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
};
module.exports = connectDB;
Heroku, AWS, 또는 DigitalOcean에 배포할 수 있습니다. MongoDB Atlas를 사용하여 클라우드 데이터베이스를 설정하고, 환경 변수를 프로덕션 환경에 맞게 구성합니다.
6. 마무리 및 확장 아이디어
이 REST API 서버 구축 단계별 튜토리얼을 통해 기본적인 RESTful API 서버를 완성했습니다. 이제 다음과 같은 기능을 추가하여 프로젝트를 확장할 수 있습니다:
- 비밀번호 재설정: 이메일 인증을 통한 비밀번호 복구 기능
- 파일 업로드: Multer를 사용한 프로필 이미지 업로드
- 페이지네이션: 대량의 데이터를 효율적으로 처리
- 검색 및 필터링: 쿼리 파라미터를 활용한 고급 검색
- 레이트 리미팅: API 남용 방지를 위한 요청 제한
- API 문서화: Swagger를 사용한 자동 API 문서 생성
- 로깅: Winston 또는 Morgan을 활용한 로그 관리
- 테스트 코드: Jest와 Supertest를 사용한 단위 및 통합 테스트
이 프로젝트는 포트폴리오로 활용하거나 실제 서비스의 백엔드로 발전시킬 수 있는 견고한 기반이 됩니다. 지속적으로 코드를 개선하고 새로운 기능을 추가하면서 실력을 향상시켜 보세요!
📚 함께 읽으면 좋은 글
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 11. 2.
🎯 REST API 서버 구축 단계별 튜토리얼
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 11. 1.
🎯 REST API 서버 구축 단계별 튜토리얼
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 10. 19.
🎯 REST API 서버 구축 단계별 튜토리얼
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 11. 4.
🎯 실시간 채팅 앱 만들기 with Socket.io
React + Node.js 풀스택 앱 배포하기 – 완성까지 한번에!
📅 2025. 11. 3.
🎯 React + Node.js 풀스택 앱 배포하기
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글에서 가장 도움이 된 부분은 어떤 것인가요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!