Node.js로 구축한 REST API의 실제 운영 경험 공유
최근 몇 년간 Node.js는 JavaScript 런타임 환경으로서 백엔드 개발에 큰 인기를 끌고 있습니다. 비동기 I/O 처리와 높은 성능 덕분에 많은 개발자들이 Node.js를 선택하고 있으며, 저 역시 REST API를 구축하는 데 이 기술을 활용해보았습니다. 이 글에서는 Node.js로 REST API를 구축하고 운영한 경험을 공유하고, 실용적인 팁과 코드 예제를 제공하겠습니다.
프로젝트 개요
저희 팀은 클라이언트 애플리케이션과 통신할 RESTful API를 구축해야 했습니다. 이 API는 사용자의 정보를 처리하고, CRUD(Create, Read, Update, Delete) 작업을 지원해야 했습니다. 데이터베이스로는 MongoDB를 선택하였고, Mongoose 라이브러리를 사용하여 데이터베이스와의 상호작용을 간편하게 처리하기로 했습니다.
환경 설정
Node.js와 Express.js를 활용하여 REST API를 구축하기 위해, 먼저 프로젝트를 초기화하고 필요한 패키지를 설치했습니다. 다음 명령어를 통해 Node.js 프로젝트를 시작했습니다.
mkdir my-api
cd my-api
npm init -y
npm install express mongoose dotenv
express는 웹 프레임워크이고, mongoose는 MongoDB와의 연결을 도와주는 ODM(Object Data Modeling) 라이브러리입니다. dotenv는 환경 변수 관리를 위한 라이브러리입니다.
기본 서버 구성
다음으로 server.js 파일을 생성하고 기본적인 Express 서버를 설정했습니다.
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.listen(PORT, () => {
console.log(Server is running on port ${PORT});
});
// MongoDB 연결
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
위 코드는 기본적인 Express 서버를 설정하고 MongoDB에 연결하는 역할을 합니다. 환경 변수 파일(.env)에는 데이터베이스 URI와 기타 설정을 저장합니다.
RESTful API 엔드포인트 구축
이제 사용자의 정보를 관리할 수 있는 RESTful API 엔드포인트를 구축해보겠습니다. 먼저 사용자 모델을 정의합니다. models/User.js 파일을 생성합니다.
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
age: { type: Number, required: true }
});
module.exports = mongoose.model('User', UserSchema);
이제 사용자를 생성, 조회, 수정, 삭제할 수 있는 엔드포인트를 추가합니다. routes/user.js 파일을 생성하고 다음과 같이 작성합니다.
const express = require('express');
const User = require('../models/User');
const router = express.Router();
// 사용자 생성
router.post('/', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).send(user);
} catch (error) {
res.status(400).send(error);
}
});
// 모든 사용자 조회
router.get('/', async (req, res) => {
try {
const users = await User.find();
res.send(users);
} catch (error) {
res.status(500).send(error);
}
});
// 특정 사용자 조회
router.get('/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(500).send(error);
}
});
// 사용자 수정
router.patch('/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(400).send(error);
}
});
// 사용자 삭제
router.delete('/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(500).send(error);
}
});
module.exports = router;
이제 server.js 파일에서 라우터를 불러와야 합니다.
const userRouter = require('./routes/user');
app.use('/api/users', userRouter);
운영 경험 및 팁
API를 운영하면서 겪었던 몇 가지 경험과 팁을 공유하겠습니다.
- 에러 처리: 각 API 요청에 대한 에러 처리를 철저히 하는 것이 중요합니다. 클라이언트가 에러 메시지를 이해할 수 있도록 적절한 상태 코드와 메시지를 반환하세요.
- 성능 최적화: 성능을 높이기 위해 MongoDB의 인덱스를 활용하고, 필요한 경우 캐싱을 구현하세요.
- 보안: API를 외부에 노출할 때는 인증 및 인가를 반드시 구현해야 합니다. JWT(JSON Web Token)를 활용한 인증 방식이 많이 사용됩니다.
- 로깅 및 모니터링: 운영 환경에서는 로깅과 모니터링을 통해 API의 상태를 점검하세요. Winston과 같은 로깅 라이브러리를 사용하면 유용합니다.
- 테스트: Jest와 같은 테스트 프레임워크를 활용하여 API 엔드포인트에 대한 단위 테스트를 작성하면, 유지보수성이 향상됩니다.
마무리
이번 글에서는 Node.js를 사용하여 REST API를 구축하고 운영하는 과정에서의 경험을 공유했습니다. 프로젝트 초기 설정부터 실제 기능 구현, 운영 팁에 이르기까지 다양한 내용을 다뤘습니다. Node.js의 비동기 처리 특성과 Express의 간결함 덕분에 빠르게 API를 구축할 수 있었습니다. 여러분도 Node.js를 활용하여 효율적인 REST API를 만들어보시기 바랍니다!