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

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

REST API 서버 구축 단계별 튜토리얼은 Node.js와 Express를 사용하여 처음부터 완전한 RESTful API 서버를 만드는 과정을 상세히 다룹니다. 백엔드 개발의 기초부터 데이터베이스 연동, 인증, 배포까지 실무에서 필요한 모든 과정을 실습하며 배울 수 있습니다. 이 튜토리얼을 따라하면 포트폴리오에 추가할 수 있는 실전 프로젝트를 완성할 수 있습니다.

1. 프로젝트 소개 및 목표

이번 REST API 서버 구축 단계별 튜토리얼에서는 사용자 관리 시스템을 갖춘 완전한 REST API를 개발합니다. CRUD(Create, Read, Update, Delete) 기능을 모두 구현하고, JWT 기반 인증을 추가하여 보안성을 확보합니다. 최종적으로는 클라우드 플랫폼에 배포하여 실제 운영 가능한 서버를 만드는 것이 목표입니다. 이 프로젝트를 통해 백엔드 개발자로서 필요한 핵심 역량을 습득하고, 프론트엔드와 연동 가능한 실용적인 API 서버를 구축할 수 있습니다.

2. 필요한 기술 스택

이 튜토리얼에서 사용할 기술 스택은 다음과 같습니다:

  • Node.js: JavaScript 런타임 환경 (v18 이상 권장)
  • Express.js: 빠르고 간결한 웹 프레임워크
  • MongoDB: NoSQL 데이터베이스 (또는 PostgreSQL)
  • Mongoose: MongoDB ODM 라이브러리
  • JWT (jsonwebtoken): 토큰 기반 인증
  • bcrypt: 비밀번호 암호화
  • dotenv: 환경 변수 관리
  • Postman: API 테스트 도구

모든 도구는 무료로 사용 가능하며, 초보자도 쉽게 따라할 수 있도록 구성되어 있습니다.

3. 프로젝트 셋업

먼저 프로젝트 디렉토리를 생성하고 필요한 패키지를 설치합니다:

# 프로젝트 디렉토리 생성
mkdir rest-api-tutorial
cd rest-api-tutorial

# package.json 초기화
npm init -y

# 필요한 패키지 설치
npm install express mongoose dotenv bcryptjs jsonwebtoken cors
npm install --save-dev nodemon

프로젝트 구조를 다음과 같이 설정합니다:

rest-api-tutorial/
├── src/
│   ├── models/
│   ├── routes/
│   ├── controllers/
│   ├── middleware/
│   └── config/
├── .env
├── .gitignore
├── server.js
└── package.json

.env 파일을 생성하여 환경 변수를 설정합니다:

PORT=5000
MONGODB_URI=mongodb://localhost:27017/rest-api-db
JWT_SECRET=your_jwt_secret_key_here

package.json의 scripts 섹션을 수정하여 개발 서버를 쉽게 실행할 수 있도록 합니다:

"scripts": {
  "start": "node server.js",
  "dev": "nodemon server.js"
}

4. 단계별 구현 과정

Step 1: 기본 서버 설정

server.js 파일을 생성하여 Express 서버의 기본 골격을 만듭니다:

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT || 5000;

// 미들웨어
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 기본 라우트
app.get('/', (req, res) => {
  res.json({ message: 'REST API 서버가 정상 작동 중입니다!' });
});

// MongoDB 연결
mongoose.connect(process.env.MONGODB_URI)
  .then(() => {
    console.log('MongoDB 연결 성공');
    app.listen(PORT, () => {
      console.log(`서버가 포트 ${PORT}에서 실행 중입니다.`);
    });
  })
  .catch((error) => {
    console.error('MongoDB 연결 실패:', error);
  });

Step 2: 데이터 모델 생성

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

Step 3: 인증 미들웨어 구현

src/middleware/auth.js 파일을 생성하여 JWT 인증 로직을 구현합니다:

const jwt = require('jsonwebtoken');
const User = require('../models/User');

const authMiddleware = async (req, res, next) => {
  try {
    // 헤더에서 토큰 추출
    const token = req.header('Authorization')?.replace('Bearer ', '');
    
    if (!token) {
      return res.status(401).json({ error: '인증 토큰이 없습니다' });
    }

    // 토큰 검증
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    const user = await User.findById(decoded.userId).select('-password');

    if (!user) {
      return res.status(401).json({ error: '사용자를 찾을 수 없습니다' });
    }

    req.user = user;
    next();
  } catch (error) {
    res.status(401).json({ error: '유효하지 않은 토큰입니다' });
  }
};

module.exports = authMiddleware;

Step 4: 컨트롤러 작성

src/controllers/authController.js 파일을 생성하여 인증 관련 로직을 처리합니다:

const User = require('../models/User');
const jwt = require('jsonwebtoken');

// JWT 토큰 생성 함수
const generateToken = (userId) => {
  return jwt.sign({ 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({ error: '이미 존재하는 사용자입니다' });
    }

    // 사용자 생성
    const user = new User({ username, email, password });
    await user.save();

    // 토큰 생성
    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({ error: '서버 오류가 발생했습니다', details: 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({ error: '이메일 또는 비밀번호가 올바르지 않습니다' });
    }

    // 비밀번호 확인
    const isPasswordValid = await user.comparePassword(password);
    if (!isPasswordValid) {
      return res.status(401).json({ error: '이메일 또는 비밀번호가 올바르지 않습니다' });
    }

    // 토큰 생성
    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({ error: '서버 오류가 발생했습니다', details: error.message });
  }
};

src/controllers/userController.js 파일을 생성하여 사용자 CRUD 기능을 구현합니다:

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

// 모든 사용자 조회
exports.getAllUsers = async (req, res) => {
  try {
    const users = await User.find().select('-password');
    res.json({ count: users.length, users });
  } catch (error) {
    res.status(500).json({ error: '사용자 조회 실패', details: error.message });
  }
};

// 특정 사용자 조회
exports.getUserById = async (req, res) => {
  try {
    const user = await User.findById(req.params.id).select('-password');
    if (!user) {
      return res.status(404).json({ error: '사용자를 찾을 수 없습니다' });
    }
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: '사용자 조회 실패', details: error.message });
  }
};

// 사용자 정보 수정
exports.updateUser = async (req, res) => {
  try {
    const { username, email } = req.body;
    const user = await User.findByIdAndUpdate(
      req.params.id,
      { username, email },
      { new: true, runValidators: true }
    ).select('-password');

    if (!user) {
      return res.status(404).json({ error: '사용자를 찾을 수 없습니다' });
    }

    res.json({ message: '사용자 정보가 업데이트되었습니다', user });
  } catch (error) {
    res.status(500).json({ error: '업데이트 실패', details: error.message });
  }
};

// 사용자 삭제
exports.deleteUser = async (req, res) => {
  try {
    const user = await User.findByIdAndDelete(req.params.id);
    if (!user) {
      return res.status(404).json({ error: '사용자를 찾을 수 없습니다' });
    }
    res.json({ message: '사용자가 삭제되었습니다' });
  } catch (error) {
    res.status(500).json({ error: '삭제 실패', details: error.message });
  }
};

Step 5: 라우트 설정

src/routes/authRoutes.js 파일을 생성합니다:

const express = require('express');
const router = express.Router();
const authController = require('../controllers/authController');

router.post('/register', authController.register);
router.post('/login', authController.login);

module.exports = router;

src/routes/userRoutes.js 파일을 생성합니다:

const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const authMiddleware = require('../middleware/auth');

router.get('/', authMiddleware, userController.getAllUsers);
router.get('/:id', authMiddleware, userController.getUserById);
router.put('/:id', authMiddleware, userController.updateUser);
router.delete('/:id', authMiddleware, userController.deleteUser);

module.exports = router;

server.js에 라우트를 등록합니다:

// 라우트 import
const authRoutes = require('./src/routes/authRoutes');
const userRoutes = require('./src/routes/userRoutes');

// 라우트 사용
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);

5. 테스트 및 배포

API 테스트

Postman을 사용하여 각 엔드포인트를 테스트합니다:

  1. 회원가입: POST http://localhost:5000/api/auth/register
    {
      "username": "testuser",
      "email": "[email protected]",
      "password": "password123"
    }
    
  2. 로그인: POST http://localhost:5000/api/auth/login
    {
      "email": "[email protected]",
      "password": "password123"
    }
    
  3. 사용자 목록 조회: GET http://localhost:5000/api/users (헤더에 Authorization: Bearer [토큰] 추가)

배포

Heroku 또는 Railway를 사용한 배포 과정:

# Git 초기화
git init
git add .
git commit -m "Initial commit"

# Heroku 배포 (Heroku CLI 설치 필요)
heroku create your-app-name
heroku config:set MONGODB_URI="your_mongodb_atlas_uri"
heroku config:set JWT_SECRET="your_jwt_secret"
git push heroku main

MongoDB Atlas를 사용하여 클라우드 데이터베이스를 설정하고, 환경 변수를 배포 플랫폼에 등록합니다. CORS 설정을 프론트엔드 도메인에 맞게 조정하여 보안을 강화합니다.

6. 마무리 및 확장 아이디어

REST API 서버 구축 단계별 튜토리얼을 통해 완전한 백엔드 시스템을 구축했습니다. 추가로 구현할 수 있는 기능들:

  • 이메일 인증: Nodemailer를 사용한 회원가입 확인
  • 파일 업로드: Multer를 활용한 프로필 이미지 업로드
  • 페이지네이션: 대용량 데이터 처리를 위한 페이징 기능
  • Rate Limiting: express-rate-limit으로 API 남용 방지
  • API 문서화: Swagger를 사용한 자동 문서 생성
  • 로깅 시스템: Winston으로 에러 추적
  • Redis 캐싱: 성능 최적화

이 프로젝트를 GitHub에 업로드하고, README 파일을 작성하여 포트폴리오로 활용하세요. 프론트엔드(React, Vue)와 연동하여 풀스택 애플리케이션으로 확장할 수도 있습니다!

📚 함께 읽으면 좋은 글

1

undefined 완벽 해결법 – 원인부터 예방까지

📂 프로젝트 아이디어
📅 2025. 9. 29.
🎯 undefined

2

React Context API 마스터하기 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 10. 1.
🎯 React Context API 마스터하기

3

Python 자동화 스크립트 작성하기 – 초보자도 쉽게 따라하는 완벽 가이드

📂 Python 튜토리얼
📅 2025. 9. 30.
🎯 Python 자동화 스크립트 작성하기

4

React 성능 최적화 완벽 가이드 – 초보자도 쉽게 따라하는 완벽 가이드

📂 React 튜토리얼
📅 2025. 9. 30.
🎯 React 성능 최적화 완벽 가이드

5

FastAPI로 REST API 만들기 – 초보자도 쉽게 따라하는 완벽 가이드

📂 Python 튜토리얼
📅 2025. 9. 30.
🎯 FastAPI로 REST API 만들기

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

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

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

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

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

REST API 서버 구축 단계별 튜토리얼에 대한 여러분만의 경험이나 노하우가 있으시나요?

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

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

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

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

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

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

💡
최신 트렌드
2025년 기준

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

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

답글 남기기