Node.js + MongoDB CRUD API 구현하기
Node.js, Express, Mongoose를 이용하여 MongoDB CRUD RESTful API를 구성하는 방법에 대해 알아보겠습니다.
Mongoose는 MongoDB를 대상으로 만들어진 promise 기반의 Node.js ODM(Object Data Mapping)이며, 이것은 Java 기반의 Hibernate, iBatis와 같은 ORM(Object Relational Mapping)과 유사한 개념입니다. built-in 쿼리를 통해 간편한 CRUD 구성이 가능하며 validation, type casting 등의 기능을 제공합니다. 또한 Express와 함께 사용하면 MVC 구현이 가능합니다.
구현 환경은 다음의 버전을 기준으로 구성하였습니다.
- Node.js v12.13.1
- MongoDB v4.4.3
- Express v4.17
1. 모듈 설치 & 디렉터리 구조 설정
1.1. Node.js App 생성
디렉터리 생성 후에 npm을 이용하여 Node.js App을 생성하고 필요한 모듈을 설치해줍니다.
$ mkdir mongodb-server
$ cd mongodb-server
$ npm init --yes
$ npm install express body-parser mongoose
React 또는 Angular Application 처럼 디렉터리 내부에 package.json 정보가 포함되어 있는 경우에는 npm init 없이 디렉터리 구조만 설정해주어도 됩니다.
package.json은 다음과 같이 설정됩니다.
{
"name": "mongodb-server",
"version": "0.0.0",
"scripts": {
...
},
"dependencies": {
...
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"mongoose": "^5.12.2",
...
},
...
}
1.2. 디렉터리 구조 설정
모듈을 설치한 이후엔 다음과 같이 디렉터리 구조를 설정해줍니다. 파일은 TypeScript(.ts)를 베이스로 하였으나 JavaScript(.js)로 설정해주어도 됩니다.
src
├── app
│ └── mongodb
│ └──config
│ │ └── config.ts
│ └── controller
│ │ └── controller.ts
│ ├── model
│ │ ├── index.ts
│ │ └── model.ts
│ └── route
│ └── route.ts
└── mongodb-server.ts
2. Web Server 설정
2.1. Express Web Server 설정
Express를 사용하여 API 사용이 가능한 Web Server를 설정해줍니다. src 디렉터리 하위에 생성한 mongodb-server.ts 파일을 다음과 같이 작성해줍니다.
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const corsOptions = {
origin: 'http://localhost:8081'
};
const PORT = process.env.PORT || 8080;
// Set CORS option
app.use(cors(corsOptions));
// Parse requests of content-type: application/json
app.use(bodyParser.json());
// Parse requests of content-type: application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// RESTful API route for DB
app.use('/', require('./app/mongodb/route/route.ts'));
// DB Connection
const db = require('./app/mongodb/model/index.ts');
db.mongoose
.connect(db.url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('db.url', db.url);
console.log('db.mongoose', db.mongoose);
console.log('db.tutorial.db', db.tutorial.db);
console.log('Database Connection Success.');
})
.catch(err => {
console.log('Database Connection Failure.', err);
process.exit();
});
// Default route for server status
app.get('/', (req, res) => {
res.json({ message: `Server is running on port ${PORT}` });
});
// Set listen port for request
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
mongodb-server.ts에서 사용한 모듈의 역할은 다음과 같습니다.
- express
RESTful API 환경을 구축하기 위해 사용하는 Node.js 웹 프레임워크입니다. - body-parser
request 구문과 req.body를 파싱하는 Node.js 미들웨어입니다. - cors
CORS 설정에 사용되는 Express 미들웨어입니다.
3. MongoDB 설정
3.1. MongoDB Connection 설정
MongoDB의 Connection을 위해 app/mongodb/config/config.ts 파일을 다음과 같이 작성해줍니다.
module.exports = {
url: 'mongodb://[username:password@][host][:port]/[defaultauthdb]?gssapiServiceName=mongodb&authSource=admin'
};
url에 작성할 항목은 다음과 같습니다.
- username: MongoDB 접속 유저명
- password: MongoDB 접속 비밀번호
- host: MongoDB IP (동일한 환경일 경우 localhost)
- port: MongoDB 포트 번호
- defaultauthdb: MongoDB 접속 DB
3.2. Mongoose 설정
Mongoose를 이용하여 schema와 model을 설정하기 위해 app/mongodb/model 디렉터리 하위의 파일들을 설정해줍니다.
Mongoose 설정을 위한 index.ts 파일은 다음과 같이 작성해줍니다.
const dbConfig = require('../config/config.ts');
const mongoose = require('mongoose');
// Use Node.js native promise
mongoose.Promise = global.Promise;
const db = {};
db.mongoose = mongoose;
db.url = dbConfig.url;
db.tutorial = require('./model.ts')(mongoose);
module.exports = db;
Mongoose는 자체적으로 mPromise를 지원하지만 deprecated 되었기 때문에 Node.js의 native promise를 사용하여 설정해줍니다.
Mongoose의 model 설정을 위한 model.ts 파일은 다음과 같이 작성해줍니다. schema명은 'tutorial'로 하였습니다.
module.exports = mongoose => {
// Set model
const Tutorial = mongoose.model(
'tutorial',
mongoose.Schema(
{
title: String,
description: String,
published: Boolean
},
{ timestamps: true }
)
);
return Tutorial;
};
예제에서 schema명은 'tutorial'로 작성하였지만 MongoDB와의 connection 이후에 생성되는 collection의 name은 뒤에 's'가 붙어서 'tutorials'로 생성되게 됩니다.
4. CRUD API Router & Controller 설정
4.1. Router 설정
Router에서 사용할 CRUD RESTful API의 HTTP Request는 다음과 같습니다.
Method | Route URL | Action |
GET | /api/tutorial | 모든 tutorial document 조회 |
GET | /api/tutorial/:id | id로 tutorial document 조회 |
POST | /api/tutorial | tutorial document 생성 |
PUT | /api/tutorial/:id | id로 tutorial document 수정 |
DELETE | /api/tutorial/:id | id로 tutorial document 삭제 |
Router 설정을 위해서 app/mongodb/route/route.ts 파일을 다음과 같이 작성해줍니다.
const router = require('express').Router();
const tutorial = require('../controller/controller.ts');
// Create document
router.post('/api/tutorial', tutorial.create);
// Retrieve all documents
router.get('/api/tutorial', tutorial.findAll);
// Retrieve single document by id
router.get('/api/tutorial/:id', tutorial.findOne);
// Update document by id
router.put('/api/tutorial/:id', tutorial.update);
// Delete document by id
router.delete('/api/tutorial/:id', tutorial.delete);
module.exports = router;
4.2. Controller 설정
Controller 설정을 위해서 app/mongodb/controller/controller.ts 파일을 다음과 같이 작성해줍니다. 앞서 작성한 route.ts 파일에서 API에 따라 호출되는 메서드들을 구현해줍니다.
const db = require('../model/index.ts');
const Tutorial = db.tutorial;
// Create document
exports.create = (req, res) => {
// Validate request
if (!req.body.title) {
res.status(400).send({
message: 'Title is empty!'
});
return;
}
// Set document
const tutorial = new Tutorial({
title: req.body.title,
description: req.body.description,
published: req.body.published ? req.body.published : false
});
// Save document
Tutorial
.save(tutorial)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message: err.message || 'Create document failure.'
});
});
};
// Retrieve all documents
exports.findAll = (req, res) => {
const title = req.query.title;
const condition = title ? { title: { $regex: new RegExp(title), $options: 'i' } } : {};
// Retrieve all documents
Tutorial.find(condition)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message: err.message || 'Retrieve document failure.'
});
});
};
// Retrieve single document
exports.findOne = (req, res) => {
const id = req.params.id;
// Retrieve single document by id
Tutorial.findById(id)
.then(data => {
if (!data) {
res.status(404).send({
message: 'Cannot find document. (id: ' + id + ')'
});
} else {
res.send(data);
}
})
.catch(err => {
res.status(500).send({
message: err.message || 'Retrieve single document failure. (id: ' + id + ')'
});
});
};
// Update document by id
exports.update = (req, res) => {
if (!req.body) {
return res.status(400).send({
message: 'Data is empty!'
});
}
// Set id
const id = req.params.id;
// Update document by id
Tutorial.findByIdAndUpdate(id, req.body, { useFindAndModify: false })
.then(data => {
if (!data) {
res.status(404).send({
message: 'Cannot update document. (id: ' + id + ')'
});
} else {
res.send({
message: 'Document updated.'
});
}
})
.catch(err => {
res.status(500).send({
message: err.message || 'Update document failure. (id: ' + id + ')'
});
});
};
// Delete document by id
exports.delete = (req, res) => {
if (!req.body) {
return res.status(400).send({
message: 'Data is empty!'
});
}
// Set id
const id = req.params.id;
// Delete document by id
Tutorial.findByIdAndRemove(id)
.then(data => {
if (!data) {
res.status(404).send({
message: 'Cannot delete document. (id: ' + id + ')'
});
} else {
res.send({
message: 'Document deleted.'
});
}
})
.catch(err => {
res.status(500).send({
message: err.message || 'Delete document failure. (id: ' + id + ')'
});
});
};
5. 서버 실행 & API 테스트
5.1. MongoDB 서버 실행
src 디렉터리 하위에 생성한 mongodb-server.ts 파일을 Node.js로 실행해줍니다.
$ node mongodb-server.ts
서버가 정상적으로 실행되면 Database Connection이 성공했다는 메시지가 출력됩니다.
브라우저에서 http://localhost:8080 url로 접속하면 다음과 같이 메시지가 출력되는 것을 확인할 수 있습니다.
5.2. CRUD API 테스트
Postman을 이용하여 다음과 같이 API 테스트를 해줍니다.
5.2.1. Create (POST)
5.2.2. Retrieve (GET)
5.2.3. Update (PUT)
5.2.4. Delete (DELETE)
이상으로 Node.js와 MongoDB를 이용하여 CRUD RESTful API를 구성하는 방법에 대해 알아봤습니다.
※ Reference
- bezkoder.com, Node.js, Express & MongoDb: Build a CRUD Rest Api example, bezkoder.com/node-express-mongodb-crud-rest-api/
- docs.mongodb.com, Connection String URI Format, docs.mongodb.com/manual/reference/connection-string/
- docs.mongodb.com, MongoDB CRUD Operations, docs.mongodb.com/manual/crud/
- poiemaweb.com, Node.js(express)와 MongoDB 연동 RESTful API - Mongoose, poiemaweb.com/mongoose
- velog.io/@yejinh, express 미들웨어 body-parser 모듈, velog.io/@yejinh/express-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-bodyParser-%EB%AA%A8%EB%93%88
- guswnsxodlf.github.io, node.js express에서 CORS 허용하기, guswnsxodlf.github.io/enable-CORS-on-express