用Node.js Express + MongoDB 写一个Restful CRUD API [个人学习]

原教学: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.js Express + MongoDB 写一个Restful CRUD API [个人学习]_第1张图片
下面渐进式完成整个项目的构建

初始化项目

开一个文件夹,例如:
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

先建立好文件夹
用Node.js Express + MongoDB 写一个Restful CRUD API [个人学习]_第2张图片
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,谢谢观看。

你可能感兴趣的:(node.js,nosql,mongodb)