Express接口综合案例(创建项目、配置常用中间件、路由设计、提取控制器模块、配置错误统一处理中间件、用户注册的数据验证,密码加密)

一、创建项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、目录结构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三、配置常用中间件

3.1 解析请求体

  • express.json()
  • express.urlencoded()

3.2 日志输出

  • morgan()
    在这里插入图片描述

3.3 为客户端提供跨域资源请求

  • cors()
    在这里插入图片描述
    在这里插入图片描述

四、路由设计

本项目的接口设计参考:https://github.com/gothinkster/realworld/tree/master/api
在这里插入图片描述

router/index.js:

const express = require('express')

const router = express.Router()

router.get('/', (req, res) => {
    
    
    res.send('Hello World')
})

// 用户相关的路由
router.use(require('./user.js'))

// 用户资料相关路由
router.use(require('./profile.js'))

// 文章相关的路由
router.use(require('./article.js'))

// 标签相关的路由
router.use(require('./tag.js'))




module.exports = router

router/user.js:

const express = require('express')
const userController = require('../controller/user.js')
const router = express.Router()


// 用户登录
router.post('/users/login', userController.login)

// 用户注册
router.post('/users', userController.register)

// 获取当前登录用户
router.get('/user', userController.getCurrentUser)

// 更新当前登录的用户资料
router.put('/user', userController.updateCurrentUser)


module.exports = router

router/article.js:

const express = require('express')
const articleController = require('../controller/article.js')
const router = express.Router()

// 获取文章列表
router.get('/articles', articleController.getArticles)

// 获取用户关注的作者的文章列表
router.get('/articles/feed', articleController.getFeedArticles)

// 获取文章
router.get('/articles/:slug', articleController.getArticle)

// 创建文章
router.post('/articles',articleController.createArticle)

// 更新文章
router.put('/articles/:slug', articleController.updateArticle)

// 删除文章
router.delete('/articles/:slug', articleController.deleteArticle)

// 为文章添加评论
router.post('/articles/:slug/comments', articleController.addComments)

// 从文章中获取评论
router.get('/articles/:slug/comments', articleController.getComments)

// 删除评论
router.delete('/articles/:slug/comments/:id', articleController.deleteComments)

// 收藏文章
router.post('/articles/:slug/favorite', articleController.favoriteArticle)

// 取消收藏文章
router.delete('/articles/:slug/favorite', articleController.unFavoriteArticle)



module.exports = router

router/profile.js:

const express = require('express')
const profileController = require('../controller/profile.js')
const router = express.Router()


// 获取用户个人资料
router.get('/profiles/:username', profileController.getProfile)

// 关注用户
router.post('/profiles/:username/follow', profileController.followUser)

// 取消关注用户
router.delete('/profiles/:username/follow', profileController.unFollowUser)


module.exports = router

router/tag.js:

const express = require('express')
const tagsController = require('../controller/tag.js')
const router = express.Router()

// 获取文章标签
router.get('/tags', tagsController.getTags)

module.exports = router

五、提取控制器模块

在这里插入图片描述

controller/user.js:

const {
    
     User } = require('../model/index.js')


// 用户登录
exports.login =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('post /users/login')
    } catch (err) {
    
    
        next(err)
    }
}

// 用户注册
exports.register =  async (req, res, next) => {
    
    
    try {
    
    
        // 1. 获取请求体数据
        console.log(req.body)
        // 2. 数据验证
        //  2.1 基本数据验证
        //  2.2 业务数据验证
        // 3. 验证通过,将数据保存到数据库
        const user = new User(req.body.user) // 构造user对象
        await user.save() // 保存到数据库
        // 4. 发送成功响应
        res.status(201).json({
    
    
            user
        })
    } catch (err) {
    
    
        next(err)
    }
}

// 获取当前登录用户
exports.getCurrentUser =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /user')
    } catch (err) {
    
    
        next(err)
    }
}

// 更新当前登录的用户资料
exports.updateCurrentUser =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('put /user')
    } catch (err) {
    
    
        next(err)
    }
}

controller/tag.js:

// 获取文章标签
exports.getTags =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /tags 获取文章标签')
    } catch (err) {
    
    
        next(err)
    }
}



controller/article.js:

// 获取文章列表
exports.getArticles =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /articles')
    } catch (err) {
    
    
        next(err)
    }
}

// 获取用户关注的作者的文章列表
exports.getFeedArticles =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /articles/feed')
    } catch (err) {
    
    
        next(err)
    }
}

// 获取文章
exports.getArticle =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /articles/:slug 获取文章')
    } catch (err) {
    
    
        next(err)
    }
}

// 创建文章
exports.createArticle =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('post /articles 创建文章')
    } catch (err) {
    
    
        next(err)
    }
}

// 更新文章
exports.updateArticle =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('put /articles/:slug 更新文章')
    } catch (err) {
    
    
        next(err)
    }
}

// 删除文章
exports.deleteArticle =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('delete /articles/:slug 删除文章')
    } catch (err) {
    
    
        next(err)
    }
}

// 为文章添加评论
exports.addComments =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('post /articles/:slug/comments 为文章添加评论')
    } catch (err) {
    
    
        next(err)
    }
}

// 从文章中获取评论
exports.getComments =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /articles/:slug/comments 从文章中获取评论')
    } catch (err) {
    
    
        next(err)
    }
}

// 删除评论
exports.deleteComments =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('delete /articles/:slug/comments/:id 删除评论')
    } catch (err) {
    
    
        next(err)
    }
}

// 收藏文章
exports.favoriteArticle =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('post /articles/:slug/favorite 收藏文章')
    } catch (err) {
    
    
        next(err)
    }
}

// 取消收藏文章
exports.unFavoriteArticle =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('delete /articles/:slug/favorite 取消收藏文章')
    } catch (err) {
    
    
        next(err)
    }
}

controller/profile.js:

// 获取用户个人资料
exports.getProfile =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('get /profiles/:username')
    } catch (err) {
    
    
        next(err)
    }
}

// 关注用户
exports.followUser =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('post /profiles/:username/follow')
    } catch (err) {
    
    
        next(err)
    }
}

// 取消关注用户
exports.unFollowUser =  async (req, res, next) => {
    
    
    try {
    
    
        // 处理请求
        res.send('delete /profiles/:username/follow')
    } catch (err) {
    
    
        next(err)
    }
}

六、配置错误统一处理中间件

在这里插入图片描述
在这里插入图片描述

七、用户注册 将数据保存到数据库 && 提取通用数据模型

在这里插入图片描述
model/index.js:
在这里插入图片描述
model/user.js:
在这里插入图片描述
model/article.js:

model/base-model.js:
在这里插入图片描述

八、数据验证

express-validator官方文档
安装:npm install express-validator
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

九、提取验证中间件模块

在这里插入图片描述
在这里插入图片描述

十、用户注册的密码加密处理

nodejs内置模块 crypto 模块提供了加密功能,实现了包括对 OpenSSL 的哈希、HMAC、加密、解密、签名、以及验证功能的一整套封装。

  • 查看 crypto 模块支持的 hash 函数:crypto.getHashes()
    在这里插入图片描述
    在这里插入图片描述
    在模型的password字段上进行md5加密:
    在这里插入图片描述
    在这里插入图片描述

关于Model模型中字段的一些属性:

  1. type:字段的类型;

  2. require:true或false,指定该字段是否必填(默认false,不是必填的);

  3. max与min:数字,只能用在Number类型,可以表示最大值与最小值是多少;

  4. maxlength与minlength:只能用于String字符串类型,表示最长或最短字符串长度;

  5. enum: [‘男’, ‘女’],可枚举类型,后边是一个数组,也就是值必须在枚举值中,并且枚举类型必须是String;

    例:sex: { type: String, enum: [ ‘男’, ‘女’ ] } sex字段的值必须在枚举值中,且必须为字符串。

  6. defalt: ‘xxx’, 默认值,如果没有传参数时,会取默认值,存入数据库。

  7. trim: true, 去除字符串两端空格(保存前对字段进行 .trim());

  8. uppercase:true , 只能用于字符串,表示把所有小写字母转为大写字母(保存前对字段进行.toUpperCase());

  9. lowercase:true , 只能用于字符串,表示把所有大写字母转为小写字母(保存前对字段进行.toLowerCase());

    例:test{ type: String, lowercase: true }。

  10. select: true/false,指定该字段在查询出的数据中是否显示,true表示查询数据过滤该字段;

  11. get: () => {} 和set:() => {},两个函数使用Object.defineProperty( ) 来定义getter、setter。

  12. validate: ()=>{ } ,为该字段添加校验。
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44827418/article/details/119345170
今日推荐