【轉】用Node.js Express + MongoDB 寫一個Restful CRUD API [我的學習]

原教學:https://www.callicoder.com/node-js-express-mongodb-restful-crud-api-tutorial/
原做者:Rajeev Singhhtml

你們好,我是小志,也能夠叫我Jason。前端

該文章不是對原文進行翻譯,只是記錄本身的一些想法。node

一直沒有用過MongoDB,想學習和了解一下NoSQL要如何運做,該如何進行CRUD等操做,找了一篇教學,發現十分簡單,記錄一下本身的學習路程。git

學習目的:用Node.js和Express創建一個Restful API, 能夠對數據進行CRUD的操做mongodb

先安裝MongoDB, https://docs.mongodb.com/manual/administration/install-community/
我本身是WINDOW安裝的,基本上就是下載MSI,而後下一步接下一步,最後等他安裝完就好。express

工具:
Express用下來的感受是輕便簡單,沒有太多複雜的操做(最少這裏用到的沒有)npm

Mongoose對MongoDB操做的工具,更詳細的說法請看原教學json

測試工具:
Postman 對API進行測試的工具, 發送各類request後端

最後項目的結構
結構.png
下面漸進式完成整個項目的構建api

初始化項目

開一個文件夾,例如:
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

先創建好文件夾
結構2.png
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,謝謝觀看。

相關文章
相關標籤/搜索