Node教程——API介面開發(Node版的CRUD通用介面的搭建)(MangoDB+Express_Version2)

BM老李發表於2020-05-19

1. 概述

時間跨度有點大,之前就跟大家嘮嗑過一些知識點,也開啟了一個Node書寫一個後臺api專案的開始,出於各種原因,遲遲沒有更新博文。現在我把這個坑填上,如果你還有閱讀過我之前的文章,我建議你先閱讀一下

博文地址https://www.cnblogs.com/BM-laoli/p/12708342.html

專案Git地址 https://github.com/BM-laoli/Node-api-Design

在接下來的專案中,我將盡量的以工作時的狀態,或者說完全按照公司工作的標準流程,來進行開發,git上分章節,建立分支都是必須學的基本技能,

2. 初始化(github相關)

我們這裡假設一種情況,就是你進到一家公司,公司新的專案還沒有開始,目前是做的舊的專案,(假設舊的專案在github上),突然你的上司跟你說,你今天做一個對某專案(這裡假設舊是我們的design)做一個CRUD介面,然後你上司丟給你一個gihub地址,那你怎麼辦?蒙圈了???,你這個時候去問人....就有點傻逼了,因為你這都不會,你還來公司幹啥?乾坐著?

好了毒雞湯灌輸完畢,接下里我們就來開始我們的專案

2.1. 設計架構的更新

  • 首先我們看看我們的之前的設計圖,再看看我們現在的資料銅架構圖

2.2 看看我們接下需要做哪些事情,

我們希望寫幾個介面對兩個資料表進行操作這兩個表是 article 還有user

  • 關於架構的設計模式還有一些規則,

大佬不要噴我,這裡就說一下,我的個人觀點,專案的架構,基本上都是MVC,既然是MVC那麼這裡就得非常的明確的分出來,(如果你學習過後臺的語言比如php或者java)那麼這個應該能非常好理解,在node中的架構是這樣的,

我們站在http傳送的報文角度,看看我們的的報文從客戶端發到我們node伺服器,經歷了哪些事情

--> 進入路由 -----> 路由接受到之後做業務處理,這裡就是(中介軟體)業務處理的邏輯就是在中介軟體做的-------> 假設你的http報文要請求資料庫的一些欄位,那麼久需要用到model層<------資料庫的dao層(在node中你可能使用的別人大神給你寫好的dao層比如mongoose,或則Knex.js等,總而言之這些東西都是為model服務的) ------>中介軟體丟擲資料next到我們的路由上------->路由通過res.send把資料丟出去,提示:在node中我們最常用的就是把傳出去的資料整成json格式,如果你還不會,彆著急我們一點點來學

2.3 克隆專案下來

git clone https://github.com/BM-laoli/Node-api-Design.git      

3. 進入業務之前的說明

3.1 想清楚在敲程式碼

我們看看啊,我們的大體的流程,理解整個的流程,丟程式碼的書寫非常的重要,這樣你就能清晰的知道自己到底在幹嘛了.

還有一點需要說明的是:這裡我們遵守這樣的一個命名規範:資料模型是大寫單數,路由引數是小寫複數比如

Article ====> articles

3.2 介面測試工具

我們使用一個vs上的一個外掛這個外掛是下面的樣子,在專案中,我講一點點的教大家使用它

4. 進入業務

4.1 設計資料庫並且完成連線

這裡我們主要乾的一個事情就是設計兩個集合(表),並且拿到他們的操作物件

  1. 新建一個分支init-database,
git checkout -b init-basese

這裡我們新建一個分支,並且配置一個忽略項檔案
.gitignore

.DS_Store
node_modules
npm-debug.log
package-lock.json

以上的程式碼表示我們在git上提交東西的時候可以忽略掉node_module,等資料夾/檔案

  1. 在molde下設計一個article表(集合),它的規則(schema)如下

/model/Article

const mongoose = require('mongoose')
const schema = new mongoose.Schema({

    title:{ type:String },
    body:{type:String}

})

module.exports = mongoose.model( 'Article',schema )
  1. 提交給git分支,並且合併一下程式碼待maseter上

git push origin init-basese

4.2 實現丟article表的增刪改查(CRUD)

首先我們依然是git出來一個分支,我們在CRUD分支下進行操作

git checkout -b CRUD

注意,這裡我在原來的基礎上做了一些修改,因為使用restClinet的時候有些欄位不能讀取出來,所有我修改了下面的程式碼

  • 在main下 我把原來的index介面改掉了,改造成了下面的這樣的格式,然後在home.index.js中也稍微做了一下修改
    /main.js
require('./API/home/index')(admin)
實際上這樣的寫法等價於。
main.use(require('./API/home/index'))

/home/index.js

module.exports = admin => {
    const express = require('express')
    const router = express.Router({})
    const Article = require('../../../../model/Article')
    

    //測試路由
    router.get('/test',(req,res)=>{
        res.send('ok')
    })

//這句use一定要加
    admin.use('/CRUD',router)
}
  • 在路由驗證器的東西上,我改掉了header.token。因為我在發生restClint的時候,不走token,而是加在了Authorization欄位中
    /Mideleware/loginPash.js
let token = req.headers.authorization;
  • 測試結果,注意這這裡我使用了restClint外掛,通過下面的圖,你應該可以非常清晰的看到如何使用這個外掛。非常方便的做介面測試

接下里就是正式的增刪改查業務流程了
特別說明:這裡我們編寫的介面要求符合REST風格,至於說明是REST風格請去百度,它看起來就是下面的這個樣子

更具REST風格來說。PUT表示更新,POST表示增加,DELET表示刪除,GET分為帶引數還有不帶引數的情況,不帶參數列示全查,待參數列示查指定內容
@uri  = http://localhost:3000/main/CRUD
@toke = eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiNWU5MTIwMTViOWI0NmYzZmE4Y2MzMjUzIiwiZXhwIjoxNTg5ODU0NTI5LCJpYXQiOjE1ODk4NTI3Mjl9.U0N1bZLUBiy2fmz1NqAF-tTelE7uO8Xld4HHFeBsbq7iY5rSNMByYUyxhC1k8ug9n_8XzChL81ruiFuwxIcOg7DXk_hdrnvpUgwwtjIPjn4kfWWVEsZGm456fo3L5cHfppOTWH5NQAtKEd7xwrhqPrEPsBUwAc7pKEAFDaGuFOc

### 
GET  http://localhost:3000/main/test

### 進行token校驗拿到我們的token,只有拿到token之後才允許進入下面的請求環節

POST http://localhost:3000/main/login
Content-Type: application/json

{
    "email":"18376621755@163.com",
    "password":"123456"
}


### 我們需要攜帶token才能發起其它的請求
GET {{uri}}/test
Authorization: {{toke}}


### 增
POST  {{uri}}/Article/
Content-Type: application/json
Authorization:{{toke}}

{
    "title":"分類測試3",
    "body":"<h1>你好我是標題2</h1>"
}

### 刪
DELETE {{uri}}/Article/5ec330fe21d3d97d5054e5bf
Authorization: {{toke}}

### 改
PUT   {{uri}}/Article/5ec32f60cd080550a4e2fba8
Content-Type: application/json
Authorization:{{toke}}

{
    "title":"修改測試--222",
    "body":"<h1>你好我是標題2</h1>"
}



### 查
GET {{uri}}/Article
Authorization:{{toke}}

### 查 根據id查
### 特別小心由於你在後臺使用了express的動態路由,所以你不必加id=xxx
GET {{uri}}/Article/5ec32f60cd080550a4e2fba8
Content-Type: application/json
Authorization:{{toke}}



/home/index.js

module.exports = admin => {
    const express = require('express')
    const router = express.Router({
        mergeParams: true //合併所有的url,如果你合併那麼那個動態的resoulce你是拿不到的
    })
    const Article = require('../../../../model/Article')

    //測試路由
    router.get('/test',(req,res)=>{
        res.send('ok')
    })

    //增
    router.post('/Article', async (req, res) => {
        const model = await Article.create(req.body)
        res.send(model)
    })

    //查
    router.get('/Article', async(req, res,next) => {
        const items = await Article.find().limit(10)
        res.send(items)
        next()
    })

    //根據id查
    router.get('/Article/:id', async(req, res) => {
        
        console.log('asdasdasd');
        console.log(req.params.id);
        const items = await Article.findById(req.params.id)
        res.send(items)
    })

    //更新(改)
    router.put('/Article/:id', async(req, res) => {
        const items = await Article.findByIdAndUpdate(req.params.id, req.body)
        res.send(items)
    })

    //根據id引數(刪)
    router.delete('/Article/:id', async(req, res) => {
        await Article.findByIdAndDelete(req.params.id, req.body)
        res.send({
            sucees: true
        })
    })

    admin.use('/CRUD',router)
}

4.3 使用RESTClinet進行介面測試

  • 測試結果如下:完美通過

4.4 收尾上傳分支到git

git push origin CRUD

4.4 抽離成一個通用的CRUD

現在老闆又給我嗎要求了,我們需要對一個名字叫做product集合(表),進行增刪改查,那麼問題來了?我們難道又要寫一個與上程式碼類似的介面嗎?
答案是非必要的,我們可以把上面的介面改成通用的CRUD,這樣我們就能很方便的使用它了,有新的需求來的時候,只需要修改資料模型就好了

  • 首先,我們在路由的地方做一層封裝

這裡呢,我們就使用到了,之前的命名約定規範,(命名規範非常的重要!!!),我們使用一個第三方外掛,實現大小寫以及單複數的轉換,然後根據轉換之後的結果去找對應的 資料模型就好了

module.exports = admin => {
    const express = require('express')
    const inflection = require('inflection')
    const router = express.Router({
        mergeParams: true //合併所有的url,如果你合併那麼那個動態的resoulce你是拿不到的
    })
++++
    //起一個到哪個臺的資源就好了,注意我們的中介軟體
    admin.use('/CRUD/rest/:resource', async(req, res, next) => {

        //轉化成單數大寫的字串形式
        let moldeName = inflection.classify(req.params.resource)
        console.log(moldeName); //categorys ===> Category
        //注意這裡的關聯查詢populate方法,裡面放的就是一個要被關聯的欄位
        req.Model = require(`../../../../model/${moldeName}`)
        req.modelNmae = moldeName
        next()
    }, router)

}


設定好一層用來的過濾中介軟體之後,那麼我們的CRUD就變成了一個通用的介面了,後續的操作API只需要變化介面的名字,變化資料庫模型就好了,非常的方便,


 //增
    router.post('/', async (req, res) => {
        const model = await req.Model.create(req.body)
        res.send(model)
    })

    //查
    router.get('/', async(req, res,next) => {
        const items = await req.Model.find().limit(10)
        res.send(items)
        next()
    })

    //根據id查
    router.get('/:id', async(req, res) => {
        
        console.log('asdasdasd');
        console.log(req.params.id);
        const items = await req.Model.findById(req.params.id)
        res.send(items)
    })

    //更新(改)
    router.put('/:id', async(req, res) => {
        const items = await req.Model.findByIdAndUpdate(req.params.id, req.body)
        res.send(items)
    })

    //根據id引數(刪)
    router.delete('/:id', async(req, res) => {
        await req.Model.findByIdAndDelete(req.params.id, req.body)
        res.send({
            sucees: true
        })
    })

接下來我們新建一個product模型進行測試
/model/Prodcut

const mongoose = require('mongoose')
const schema = new mongoose.Schema({

    product_name:{ type:String },
    category:{type:String}

})

module.exports = mongoose.model( 'Product',schema )

測試結果如下

相關文章