• Node教程——API接口开发(Node版的CRUD通用接口的搭建)(MangoDB+Express_Version2)


    1. 概述

    时间跨度有点大,之前就跟大家唠嗑过一些知识点,也开启了一个Node书写一个后台api项目的开始,出于各种原因,迟迟没有更新博文。现在我把这个坑填上,如果你还有阅读过我之前的文章,我建议你先阅读一下

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

    项目Git地址 https://github.com/BM-laoli/Node-api-Design 所有代码已经分章节的放在了github供需要的朋友参考

    在接下来的项目中,我将尽量的以工作时的状态,或者说完全按照公司工作的标准流程,来进行开发,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 )
    

    测试结果如下

  • 相关阅读:
    2013年元旦新年好
    2012第52周三阴雨
    2013第1周四雪
    2013年元旦新年好
    2013第1周三阴冷
    2012第52周日晴冷
    2012周六补记
    PHP怎么调用其他类的方法
    面向对象复习笔记(一)
    Laravel 引入自定义类库或第三方类库
  • 原文地址:https://www.cnblogs.com/BM-laoli/p/12913498.html
Copyright © 2020-2023  润新知