Node tutorial-API interface development (MangoDB + Express)

git source code

Note: The source code has been uploaded to github, and the warehouse address is:  https://github.com/BM-laoli/Node-api-Design

Module dependency graph

1. Outline

  • Outline:
    About the architecture,
    1. First of all, we have an app.js which is the starting point of the root route, which is used to initially enter
      its functions:
      1.1
      Import module to create a basic website server, 1.2 Import bodyPasser, filter and process our post request
      1.3 Import database connection
      1.4 Open the route

    2. Here is another main.js, which is in my route folder.
      2.1 What needs to be done? Do a second intercept here and then distribute routing.
      2.2 Introduce two logic processing modules. When the request is sent, if it is not login then we You need to verify the token.
      2.3 If you are accessing the login, we need to send the post data to process the verification, and then take the token.
      2.4 If there is a token, then visit 2.2 Other routing paths that are not logi here, the verification is Passed, so we can assign various interfaces

    3. Detailed explanation assistance, tool code
      3.1 Here are some tools we need in the mainline logic
      3.2 Middleware Middleware, there are two tools, one is to generate a token and a verification token
      3.3 The functions in 3.2 need to depend on the model The jwt tool under a util generates tokens based on two key pairs
      3.4 We also have two tools, content to create a database link, create initialization data and development data operation objects

Two, display interface API documentation

1.1 Login

Request address Request method
/main/login POST
parameter name Required Parameter Description
email Yes mailbox
password Yes password
{
	"status": 200,
	"msg": "登陆成功",
	"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiNWU5MTIwMTViOWI0NmYzZmE4Y2MzMjUzIiwiZXhwIjoxNTg2OTUyMzk1LCJpYXQiOjE1ODY5NTA1OTV9.IsprCaQ_gZRh0BzS8SnAd0iJ27BOpOEb-ZGn0bTlwHVPTiYPK50wiEOL_0aAYINfNT_Mfvb726l3CpiHG9lsJ45m4eqhPeJz9TbAeQj8-ST3CAkYLrD0fhgRG9YiQ5kjVpygdR8NZEWEUV7ux-moyYe7wCoVzN9mbvAkFF3IYG0" } 

1.2 Test with token

Request address Request method
/main/text get
parameter name Required Parameter Description
token Yes Your token needs to be attached. In the request header
no no The interface does not need to pass parameters
{
	"status": 200,
	"msg": "登陆成功"
}

Note: The above is the most basic content of Node write interface. Can expand more interfaces on this content

Second, the detailed explanation of the app.js module

app.js

//引入模块,创建简单服务器
const express = require('express');
//引入路径处理模块 const path = require('path'); //引入注意使用第三方模块处理post const bodyPaser = require('body-parser') // 引入数据库连接 不需要返回值 require('./model/content') //创建服务器 const app = express(); /*//初始化数据库,注意reque的时候 会自动执行引入的js文件 require('./model/create') */ //前往小心这个要放在所有的use前面,解析我们的post请求数据 app.use(bodyPaser.urlencoded({ extended: false })); //处理静态资源路径 const DataPath = path.join(__dirname, 'public'); //这个我们后面是有用的,用来操作媒体数据,最重要的就是这个路径还有这个静态资源对象 const StaticUtils = express.static(path.join(__dirname, 'public')); //拿到路由操作对象 const main = require('./route/mian/main'); //开放接口路径 //拦截请求开始匹配路由 app.use('/dataPath', (req, res) => { res.status(200).send(JSON.stringify({ 'dataPath': DataPath })) }) app.use(StaticUtils); app.use('/main', main) //监听端口 app.listen(3000) console.log('服务器开启'); 

Third, main.js secondary routing interception module

main.js

const express = require('express')

//业务逻辑
const guard = require('../../Middleware/loginGuard') const loginPash = require('../../Middleware/loginPash') //创建路由对象 const admin = express.Router() //验证token admin.use(loginPash) //登录路由处理 admin.post('/login', guard) //首先要验证,然后才是放行到对应的路由接口里面取 admin.get('/text', require('./API/home/index')) module.exports = admin; 
  • A simple test module carried (you can follow this model, write more API interface function modules)
    home / index.js
module.exports = async(req, res) => {
    res.send({ status: 200, msg: '登陆成功', }); } 

Fourth, auxiliary tools (emphasis !!!)

  • Database connection, design and initial creation module
    model / content.js && model / create.js

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/blog')
    .then(() => { console.log('数据库连接成功'); }) .catch((erro) => { console.log(erro); }) 
 const mongoose = require('mongoose');

 const bcrypt = require('bcrypt') /*使用MongDB数据库,设计数据第一步(代码角度分析) 1.设定规则,Schema构造器,Schema的构造函数就是规则,注意规则是一系列对象 2.创建数据 */ const userSchema = new mongoose.Schema({ username: { type: String, required: true, min: 2, max: 10 }, email: { type: String, //注意 我们的邮箱凭据是用户登录的令牌,我们需要指定他为唯一的 unique: true, //这个时候,在插入的时候如果有重复的就给你抱一个错误 }, password: { type: String, required: true, }, role: { //需要说明一下,这个地方角色,我们硬性规定,超级管理员是admin普通用户是normal,为什么不用01?因为这里string了 type: String, required: true }, state: { //我们使用O1状态来设计这个数据字段,默认值是0。0是启用状态 type: Number, default: 0 } }) //使用规则创建集合, //一定要注意,我们的User就是代表了我目前最user数据集合,后期的增删改查我们都需要用到这个东西,所有我们暴露出去给路由业务使用 const User = mongoose.model('User', userSchema) //我们再来复习一下,如何用同步的方式获取异步的api结果?使用async 还有awit就可以 async function createUser() { const salt = await bcrypt.genSalt(10) const pass = await bcrypt.hash('123456', salt) const user = await User.create({ username: 'lli', email: '[email protected]', password: pass, role: 'admin', state: 0, }) } // createUser() /* // 初始化用户,注意我们的create返回的是一个promies User.create({ username: 'bmlaoli', email: '[email protected]', password: '123456', role: 'admin', state: 0, }) .then(() => { console.log('用户创建成功'); }) .catch((error) => { console.log('用户创建失败'); })*/ //注意啊,es6中如果键值对的名字是一样的就可以省略值。由于我们后期还会做更多的数据集合,于是乎我这里需要暴露一个对象出去 module.exports = { User } 
  • Another important tool module for creating tokens is based on the two key pair files
    jwt.js in the folder


/*
 *描述:以下是jwt工具,生成用于访问验证的token 
 */

// 引入模块依赖
const fs = require('fs'); const path = require('path'); const jwt = require('jsonwebtoken'); // 创建 token 类 class Jwt { constructor(data) { this.data = data; } //生成token generateToken() { let data = this.data; let created = Math.floor(Date.now() / 1000); let cert = fs.readFileSync(path.join(__dirname, '../../pem/private_key.pem')); //私钥 可以自己生成,注意这里要使用 密钥对,请求百度下载,两对密钥对 let token = jwt.sign({ data, exp: created + 60 * 30, }, cert, { algorithm: 'RS256' }); return token; } // 校验token verifyToken() { let token = this.data; let cert = fs.readFileSync(path.join(__dirname, '../../pem/public_key.pem')); //公钥 可以自己生成 let res; try { let result = jwt.verify(token, cert, { algorithms: ['RS256'] }) || {}; let { exp = 0 } = result, current = Math.floor(Date.now() / 1000); if (current <= exp) { res = result.data || {}; } } catch (e) { res = 'err'; } return res; } } module.exports = Jwt; 
  • Next is two specific token verification function modules.
    I put them in the middleware folder
    loginGuard.js && loginPash.js
const JwtUtil = require('../model/util/jwt')
const { User } = require('../model/create') const bcrypt = require('bcrypt') const guard = async(req, res, next) => { //注意使用第三方模块处理post //进图具体的业务逻辑,解构出来我们需要的东西 const { email, password, _id } = req.body; //注意啊,由于我们的中间件处理的请求于是乎我们的req身上就有这个处理的所有数据了,这个之前有说过 console.log(req.body); if (email.trim().length == 0 || password.trim().length == 0) { res.status(400).send( JSON.stringify({ message: '邮箱或密码错误' }) ) //注意send自动把状态码设置成了200,所以你需要改一下 return } //如果用户存在就先找到这个用户额信息,注意这里的这个异步await let user = await User.findOne({ email }); //这里的user就是指向当前查询出来的数据文档对象 if (user) { //比对操作,第一个参数是一个明文密码,第二个参数我们查询出来的加密密码 ,方法返回一个Boolean值,对比成功就是true,异步api可以直接加await const isValid = await bcrypt.compare(password, user.password) if (isValid) { //用户校验成功,添加tooken // 登陆成功,添加token验证 let _id = user._id.toString(); // 将用户id传入并生成token let jwt = new JwtUtil(_id); let token = jwt.generateToken(); // 将 token 返回给客户端 res.send({ status: 200, msg: '登陆成功', token: token }); //校验成功就 next() } else { res.status(400).send( JSON.stringify({ message: '邮箱或密码错误' }) ) } } else { res.status(400).send( JSON.stringify({ message: '邮箱或密码错误' }) ) } } module.exports = guard 

loginPash.js


const JwtUtil = require('../model/util/jwt')





//验证token
const loginPash = function(req, res, next) { // 我这里知识把登陆和注册请求去掉了,其他的多有请求都需要进行token校验 if (req.url != '/login?') { let token = req.headers.token; let jwt = new JwtUtil(token); let result = jwt.verifyToken(); // 如果考验通过就next,否则就返回登陆信息不正确 if (result == 'err') { console.log(result); console.log(req.url); res.send({ status: 403, msg: '登录已过期,请重新登录' }); // res.render('login.html'); } else { next(); } } else { next(); } }; module.exports = loginPash; 

5. Finally, we will sort out the relationship between these modules

In fact, this set of interfaces is down, I compare the chicken, and spent two days of spare time. Since I did n’t touch the design of the interface very much, I did n’t know much about some design patterns and concepts in the background. I took a lot of detours. What I wrote is that I wrote three notes, more than 2,000 lines, and repeated the changes before they took shape. I hope that the boss will raise your finger and point out the maze. I also hope that this introductory document will bring you gains. Use the model here to develop more interfaces. Stay tuned.

  • Reference relationship of each module, use case diagram

git source code

Note: The source code has been uploaded to github, and the warehouse address is:  https://github.com/BM-laoli/Node-api-Design

Module dependency graph

1. Outline

  • Outline:
    About the architecture,
    1. First of all, we have an app.js which is the starting point of the root route, which is used to initially enter
      its functions:
      1.1
      Import module to create a basic website server, 1.2 Import bodyPasser, filter and process our post request
      1.3 Import database connection
      1.4 Open the route

    2. Here is another main.js, which is in my route folder.
      2.1 What needs to be done? Do a second intercept here and then distribute routing.
      2.2 Introduce two logic processing modules. When the request is sent, if it is not login then we You need to verify the token.
      2.3 If you are accessing the login, we need to send the post data to process the verification, and then take the token.
      2.4 If there is a token, then visit 2.2 Other routing paths that are not logi here, the verification is Passed, so we can assign various interfaces

    3. Detailed explanation assistance, tool code
      3.1 Here are some tools we need in the mainline logic
      3.2 Middleware Middleware, there are two tools, one is to generate a token and a verification token
      3.3 The functions in 3.2 need to depend on the model The jwt tool under a util generates tokens based on two key pairs
      3.4 We also have two tools, content to create a database link, create initialization data and development data operation objects

Two, display interface API documentation

1.1 Login

Request address Request method
/main/login POST
parameter name Required Parameter Description
email Yes mailbox
password Yes password
{
	"status": 200,
	"msg": "登陆成功",
	"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiNWU5MTIwMTViOWI0NmYzZmE4Y2MzMjUzIiwiZXhwIjoxNTg2OTUyMzk1LCJpYXQiOjE1ODY5NTA1OTV9.IsprCaQ_gZRh0BzS8SnAd0iJ27BOpOEb-ZGn0bTlwHVPTiYPK50wiEOL_0aAYINfNT_Mfvb726l3CpiHG9lsJ45m4eqhPeJz9TbAeQj8-ST3CAkYLrD0fhgRG9YiQ5kjVpygdR8NZEWEUV7ux-moyYe7wCoVzN9mbvAkFF3IYG0" } 

1.2 Test with token

Request address Request method
/main/text get
parameter name Required Parameter Description
token Yes Your token needs to be attached. In the request header
no no The interface does not need to pass parameters
{
	"status": 200,
	"msg": "登陆成功"
}

Note: The above is the most basic content of Node write interface. Can expand more interfaces on this content

Second, the detailed explanation of the app.js module

app.js

//引入模块,创建简单服务器
const express = require('express');
//引入路径处理模块 const path = require('path'); //引入注意使用第三方模块处理post const bodyPaser = require('body-parser') // 引入数据库连接 不需要返回值 require('./model/content') //创建服务器 const app = express(); /*//初始化数据库,注意reque的时候 会自动执行引入的js文件 require('./model/create') */ //前往小心这个要放在所有的use前面,解析我们的post请求数据 app.use(bodyPaser.urlencoded({ extended: false })); //处理静态资源路径 const DataPath = path.join(__dirname, 'public'); //这个我们后面是有用的,用来操作媒体数据,最重要的就是这个路径还有这个静态资源对象 const StaticUtils = express.static(path.join(__dirname, 'public')); //拿到路由操作对象 const main = require('./route/mian/main'); //开放接口路径 //拦截请求开始匹配路由 app.use('/dataPath', (req, res) => { res.status(200).send(JSON.stringify({ 'dataPath': DataPath })) }) app.use(StaticUtils); app.use('/main', main) //监听端口 app.listen(3000) console.log('服务器开启'); 

Third, main.js secondary routing interception module

main.js

const express = require('express')

//业务逻辑
const guard = require('../../Middleware/loginGuard') const loginPash = require('../../Middleware/loginPash') //创建路由对象 const admin = express.Router() //验证token admin.use(loginPash) //登录路由处理 admin.post('/login', guard) //首先要验证,然后才是放行到对应的路由接口里面取 admin.get('/text', require('./API/home/index')) module.exports = admin; 
  • A simple test module carried (you can follow this model, write more API interface function modules)
    home / index.js
module.exports = async(req, res) => {
    res.send({ status: 200, msg: '登陆成功', }); } 

Fourth, auxiliary tools (emphasis !!!)

  • Database connection, design and initial creation module
    model / content.js && model / create.js

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/blog')
    .then(() => { console.log('数据库连接成功'); }) .catch((erro) => { console.log(erro); }) 
 const mongoose = require('mongoose');

 const bcrypt = require('bcrypt') /*使用MongDB数据库,设计数据第一步(代码角度分析) 1.设定规则,Schema构造器,Schema的构造函数就是规则,注意规则是一系列对象 2.创建数据 */ const userSchema = new mongoose.Schema({ username: { type: String, required: true, min: 2, max: 10 }, email: { type: String, //注意 我们的邮箱凭据是用户登录的令牌,我们需要指定他为唯一的 unique: true, //这个时候,在插入的时候如果有重复的就给你抱一个错误 }, password: { type: String, required: true, }, role: { //需要说明一下,这个地方角色,我们硬性规定,超级管理员是admin普通用户是normal,为什么不用01?因为这里string了 type: String, required: true }, state: { //我们使用O1状态来设计这个数据字段,默认值是0。0是启用状态 type: Number, default: 0 } }) //使用规则创建集合, //一定要注意,我们的User就是代表了我目前最user数据集合,后期的增删改查我们都需要用到这个东西,所有我们暴露出去给路由业务使用 const User = mongoose.model('User', userSchema) //我们再来复习一下,如何用同步的方式获取异步的api结果?使用async 还有awit就可以 async function createUser() { const salt = await bcrypt.genSalt(10) const pass = await bcrypt.hash('123456', salt) const user = await User.create({ username: 'lli', email: '[email protected]', password: pass, role: 'admin', state: 0, }) } // createUser() /* // 初始化用户,注意我们的create返回的是一个promies User.create({ username: 'bmlaoli', email: '[email protected]', password: '123456', role: 'admin', state: 0, }) .then(() => { console.log('用户创建成功'); }) .catch((error) => { console.log('用户创建失败'); })*/ //注意啊,es6中如果键值对的名字是一样的就可以省略值。由于我们后期还会做更多的数据集合,于是乎我这里需要暴露一个对象出去 module.exports = { User } 
  • Another important tool module for creating tokens is based on the two key pair files
    jwt.js in the folder


/*
 *描述:以下是jwt工具,生成用于访问验证的token 
 */

// 引入模块依赖
const fs = require('fs'); const path = require('path'); const jwt = require('jsonwebtoken'); // 创建 token 类 class Jwt { constructor(data) { this.data = data; } //生成token generateToken() { let data = this.data; let created = Math.floor(Date.now() / 1000); let cert = fs.readFileSync(path.join(__dirname, '../../pem/private_key.pem')); //私钥 可以自己生成,注意这里要使用 密钥对,请求百度下载,两对密钥对 let token = jwt.sign({ data, exp: created + 60 * 30, }, cert, { algorithm: 'RS256' }); return token; } // 校验token verifyToken() { let token = this.data; let cert = fs.readFileSync(path.join(__dirname, '../../pem/public_key.pem')); //公钥 可以自己生成 let res; try { let result = jwt.verify(token, cert, { algorithms: ['RS256'] }) || {}; let { exp = 0 } = result, current = Math.floor(Date.now() / 1000); if (current <= exp) { res = result.data || {}; } } catch (e) { res = 'err'; } return res; } } module.exports = Jwt; 
  • Next is two specific token verification function modules.
    I put them in the middleware folder
    loginGuard.js && loginPash.js
const JwtUtil = require('../model/util/jwt')
const { User } = require('../model/create') const bcrypt = require('bcrypt') const guard = async(req, res, next) => { //注意使用第三方模块处理post //进图具体的业务逻辑,解构出来我们需要的东西 const { email, password, _id } = req.body; //注意啊,由于我们的中间件处理的请求于是乎我们的req身上就有这个处理的所有数据了,这个之前有说过 console.log(req.body); if (email.trim().length == 0 || password.trim().length == 0) { res.status(400).send( JSON.stringify({ message: '邮箱或密码错误' }) ) //注意send自动把状态码设置成了200,所以你需要改一下 return } //如果用户存在就先找到这个用户额信息,注意这里的这个异步await let user = await User.findOne({ email }); //这里的user就是指向当前查询出来的数据文档对象 if (user) { //比对操作,第一个参数是一个明文密码,第二个参数我们查询出来的加密密码 ,方法返回一个Boolean值,对比成功就是true,异步api可以直接加await const isValid = await bcrypt.compare(password, user.password) if (isValid) { //用户校验成功,添加tooken // 登陆成功,添加token验证 let _id = user._id.toString(); // 将用户id传入并生成token let jwt = new JwtUtil(_id); let token = jwt.generateToken(); // 将 token 返回给客户端 res.send({ status: 200, msg: '登陆成功', token: token }); //校验成功就 next() } else { res.status(400).send( JSON.stringify({ message: '邮箱或密码错误' }) ) } } else { res.status(400).send( JSON.stringify({ message: '邮箱或密码错误' }) ) } } module.exports = guard 

loginPash.js


const JwtUtil = require('../model/util/jwt')





//验证token
const loginPash = function(req, res, next) { // 我这里知识把登陆和注册请求去掉了,其他的多有请求都需要进行token校验 if (req.url != '/login?') { let token = req.headers.token; let jwt = new JwtUtil(token); let result = jwt.verifyToken(); // 如果考验通过就next,否则就返回登陆信息不正确 if (result == 'err') { console.log(result); console.log(req.url); res.send({ status: 403, msg: '登录已过期,请重新登录' }); // res.render('login.html'); } else { next(); } } else { next(); } }; module.exports = loginPash; 

5. Finally, we will sort out the relationship between these modules

In fact, this set of interfaces is down, I compare the chicken, and spent two days of spare time. Since I did n’t touch the design of the interface very much, I did n’t know much about some design patterns and concepts in the background. I took a lot of detours. What I wrote is that I wrote three notes, more than 2,000 lines, and repeated the changes before they took shape. I hope that the boss will raise your finger and point out the maze. I also hope that this introductory document will bring you gains. Use the model here to develop more interfaces. Stay tuned.

  • Reference relationship of each module, use case diagram

Guess you like

Origin www.cnblogs.com/guoguo251/p/12709970.html