原教学:https://www.callicoder.com/node-js-express-mongodb-restful-crud-api-tutorial/
原作者:Rajeev Singh
大家好,我是小志,也可以叫我Jason。
该文章不是对原文进行翻译,只是记录自己的一些想法。
一直没有用过MongoDB,想学习和了解一下NoSQL要如何运作,该如何进行CRUD等操作,找了一篇教学,发现十分简单,记录一下自己的学习路程。
学习目的:用Node.js和Express建立一个Restful API, 可以对数据进行CRUD的操作
先安装MongoDB, https://docs.mongodb.com/manual/administration/install-community/
我自己是WINDOW安装的,基本上就是下载MSI,然后下一步接下一步,最后等他安装完就好。
工具:
Express用下来的感觉是轻便简单,没有太多复杂的操作(最少这里用到的没有)
Mongoose对MongoDB操作的工具,更详细的说法请看原教学
测试工具:
Postman 对API进行测试的工具, 发送各种request
初始化项目
开一个文件夹,例如:
node-easy-notes-app
初始化NPM
npm init
name: (node-easy-notes-app)
version: (1.0.0)
description: Never miss a thing in Life. Take notes quickly. Organize and keep track of all your notes.
entry point: (index.js) server.js
test command:
git repository:
keywords: Express RestAPI MongoDB Mongoose Notes
author: callicoder
license: (ISC) MIT
About to write to /Users/rajeevkumarsingh/node-easy-notes-app/package.json:
{
"name": "node-easy-notes-app",
"version": "1.0.0",
"description": "Never miss a thing in Life. Take notes quickly. Organize and keep track of all your notes.",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"Express",
"RestAPI",
"MongoDB",
"Mongoose",
"Notes"
],
"author": "callicoder",
"license": "MIT"
}
Is this ok? (yes) yes
比较需要留意的是,定义了项目的entry point.
在下面运行的时候,会以server.js作为入口,运行整个程序。
安装express, body-parser, mongoose
npm install express body-parser mongoose --save
目前结构
node-easy-notes-app
└── node_modules/
└── package.json
在ROOT下,开一个server.js的文件,复制下面的内容
const express = require('express');
const bodyParser = require('body-parser');
// 创建express app
const app = express();
// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }))
// parse requests of content-type - application/json
app.use(bodyParser.json())
// define a simple route
app.get('/', (req, res) => {
res.json({"message": "Welcome to EasyNotes application. Take notes quickly. Organize and keep track of all your notes."});
});
// listen for requests
app.listen(3000, () => {
console.log("Server is listening on port 3000");
});
上面的内容定义了一个简单的服务器
监听3000端口
bodyParser是用来存取request和response的工具
$ node server.js
Server is listening on port 3000
正常运行的话,会看到上面监听3000端口的内容
console.log("Server is listening on port 3000");
一个简单的Express Server就建立起来了。
可以通过localhost:3000来访问
{
"message": "Welcome to EasyNotes application. Take notes quickly. Organize and keep track of all your notes."
}
连接MongoDB
先建立好文件夹
config里database.config.js放MongoDB连接的URL
module.exports = {
url: 'mongodb://localhost:27017/easy-notes'
}
在server.js的app.use(bodyParser.json())后面,复制下面的代码,用于连接MongoDB
// Configuring the database
const dbConfig = require('./config/database.config.js');
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
// Connecting to the database
mongoose.connect(dbConfig.url, {
useNewUrlParser: true,
//Solve DeprecationWarning
useFindAndModify: false,
useUnifiedTopology: true
}).then(() => {
console.log("Successfully connected to the database");
}).catch(err => {
console.log('Could not connect to the database. Exiting now...', err);
process.exit();
});
这一段是为了避免DeprecationWarning
//Solve DeprecationWarning
useFindAndModify: false,
useUnifiedTopology: true
app/models/note.model.js
const mongoose = require('mongoose');
const NoteSchema = mongoose.Schema({
title: String,
content: String
}, {
timestamps: true
});
module.exports = mongoose.model('Note', NoteSchema);
通过mongoose定义Note的Schema
options: {timestamps: true}
自动添加了createdAt和updatedAt
相对于relational database方便了不少,而且不用特意去写SQL创建表格
虽然也用过JAVA的hibernate但是感觉别限制的死死的,很不方便。(刚入职的时候,个人能力也不是很强,去看在用hibernate的老项目,实在捉急)
app/routes/note.route.js
module.exports = (app) => {
const notes = require('../controllers/note.controller.js');
// Create a new Note
app.post('/notes', notes.create);
// Retrieve all Notes
app.get('/notes', notes.findAll);
// Retrieve a single Note with noteId
app.get('/notes/:noteId', notes.findOne);
// Update a Note with noteId
app.put('/notes/:noteId', notes.update);
// Delete a Note with noteId
app.delete('/notes/:noteId', notes.delete);
}
这边先写route,是因为controller包括CRUD,会比较长,所以先写route
从route也能看到一些controller的功能
create, findAll, findOne, update, delete
route只不过是把
post, get, put,delete
跟controller连接起来
app/controllers/note.controller.js
const Note = require('../models/note.model.js');
// Create and Save a new Note
exports.create = (req, res) => {
// Validate request
if(!req.body.content) {
return res.status(400).send({
message: "Note content can not be empty"
});
}
// Create a Note
const note = new Note({
title: req.body.title || "Untitled Note",
content: req.body.content
});
// Save Note in the database
note.save()
.then(data => {
res.send(data);
}).catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while creating the Note."
});
});
};
// Retrieve and return all notes from the database.
exports.findAll = (req, res) => {
Note.find()
.then(notes => {
res.send(notes);
}).catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving notes."
});
});
};
// Find a single note with a noteId
// Find a single note with a noteId
exports.findOne = (req, res) => {
Note.findById(req.params.noteId)
.then(note => {
if(!note) {
return res.status(404).send({
message: "Note not found with id " + req.params.noteId
});
}
res.send(note);
}).catch(err => {
if(err.kind === 'ObjectId') {
return res.status(404).send({
message: "Note not found with id " + req.params.noteId
});
}
return res.status(500).send({
message: "Error retrieving note with id " + req.params.noteId
});
});
};
// Update a note identified by the noteId in the request
exports.update = (req, res) => {
// Validate Request
if(!req.body.content) {
return res.status(400).send({
message: "Note content can not be empty"
});
}
// Find note and update it with the request body
Note.findByIdAndUpdate(req.params.noteId, {
title: req.body.title || "Untitled Note",
content: req.body.content
}, {new: true})
.then(note => {
if(!note) {
return res.status(404).send({
message: "Note not found with id " + req.params.noteId
});
}
res.send(note);
}).catch(err => {
if(err.kind === 'ObjectId') {
return res.status(404).send({
message: "Note not found with id " + req.params.noteId
});
}
return res.status(500).send({
message: "Error updating note with id " + req.params.noteId
});
});
};
// Delete a note with the specified noteId in the request
exports.delete = (req, res) => {
Note.findByIdAndRemove(req.params.noteId)
.then(note => {
if(!note) {
return res.status(404).send({
message: "Note not found with id " + req.params.noteId
});
}
res.send({message: "Note deleted successfully!"});
}).catch(err => {
if(err.kind === 'ObjectId' || err.name === 'NotFound') {
return res.status(404).send({
message: "Note not found with id " + req.params.noteId
});
}
return res.status(500).send({
message: "Could not delete note with id " + req.params.noteId
});
});
};
导入note.model.js使用Mongoose的API 进行CRUD的操作
其中
findByIdAndUpdate(
:id,
data:{...},
options:{new: true}
).then(
options.new
?updatedNote
:originalNote
)
options:{new: true}说的是回传的note会是更新状态后的Note
如果不定义,或者new: false
则会回传还没更新的Note.
Mongoose API
最后用Postman对API进行测试
超简单的Restful API接口就写好了
测试部分就不费篇章叙述了,下一个目标是用Vue+ElementUI去把前端写起来,再扩张一下这个后端,写一个比较简单的前后端结合的项目。
我是小志,也可以叫我Jason,谢谢观看。