Node-express项目--个人简历:搭建posts接口并实现评论点赞以及相关功能

Posted 安之ccy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node-express项目--个人简历:搭建posts接口并实现评论点赞以及相关功能相关的知识,希望对你有一定的参考价值。

功能描述:

  1. 用户发布一条post信息,其他用户(包括自己)可以对这条post信息进行点赞、评论、取消点赞、删除评论
  2. 用户可以删除自己发布的post信息,但不能删除其他用户发布的post
  3. 用户可以取消自己点的赞、删除自己的评论,不能删除其他用户点的赞,不能删除其他用户的评论
  4. 可以查看所有评论,或某条评论,不限用户

注:

  • 一些接口需要判断当前用户身份才能确定权限,因此需要用户登录,借用token来辅助验证身份;
  • 项目登录需要输入邮箱和密码,邮箱我用了test@test.comtest2@test.com
  • 为了方便书写,文章中我都用"账号test"来指代test@test.com用户,用"账号test2"来指代test2@test.com用户。具体可以查看之前的几篇文章,谢谢支持

基本搭建
      接口字段信息
      定义数据格式
      创建路由文件
      使用posts接口
      路由连通性测试

创建post信息添加接口
      路由编写
      验证编写
      使用验证
      postman测试

获取post信息
      获取所有post信息
      获取单条post

删除单条post信息

点赞接口
      创建点赞
      取消点赞

评论接口
      创建评论
      取消评论

基本搭建

接口字段信息

字段名解释
user发布者
name发布者名字/昵称,可选
avatar发布者头像,可选
text发布文本
data发布日期
likes点赞数,包含点赞id,点赞者id
comments评论,包含:评论id,评论者id,评论文本,评论日期等

定义数据格式

在module文件夹下新建文件post.js,定义posts接口数据格式

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const postSchema = new Schema({
    user: {
        type: Schema.Types.ObjectId,
        ref: "users"
    },
    text: {
        type: String,
        require: true
    },
    name: {
        type: String
    },
    likes: [{
        user: {
            type: Schema.Types.ObjectId,
            ref: "users"
        }
    }],
    avatar: {
        type: String
    },
    comments: [{
        user: {
            type: Schema.Types.ObjectId,
            ref: "users"
        },
        name: {
            type: String
        },
        avatar: {
            type: String
        },
        text: {
            type: String,
            require: true
        },
        date: {
            type: Date,
            default: Date.now()
        }
    }],
    date: {
        type: Date,
        default: Date.now()
    }
})

module.exports = Post = mongoose.model("post", postSchema);

创建路由文件

在routes/api下创建新文件post.js,作为posts接口的文件

const express = require("express");
const router = express.Router();

const mongoose = require('mongoose');
//引入需要的表
const User = require("../../module/User");
const Profile = require("../../module/Profile");
const Posts = require("../../module/Post");
const passport = require("passport");

//$route GET api/posts/test
//@desc 测试post的路由是否可以正常使用
//@access public
router.get('/test', (req, res) => {
    res.json({ msg: "post works" })
})
// 导出路由
module.exports = router;

使用posts接口

// 引入posts接口
const posts = require("./routes/api/post");
// 使用中间件
app.use("/api/posts",posts);

路由连通性测试

postman中:
在这里插入图片描述
提示posts接口工作,代表路由搭建正确,可以进行后续工作


创建post信息添加接口

路由编写

路由文件post.js中:

  • 只有登录用户才能发布post信息,并且发布的post信息与用户绑定,需要使用token验证
  • 将发布的post信息保存至数据库
//$route POST api/posts
//@desc 创建post接口
//@access private
router.post("/", passport.authenticate("jwt", { session: false }), (req, res) => {

	// 存储用户输入的数据
    const newPost = new Posts({
        user:req.user.id,
        text:req.body.text,
        name:req.body.name,
        name:req.body.name,
        avatar:req.body.avatar
    })
    // 将数据存储到数据库
    newPost.save().then(post=>{
        res.json(post)
    })
    .catch(err=>res.json(err))

})

验证编写

  • 验证输入的数据格式,格式不正确时给出提示
  • 在定义数据时,指定text字段不能为空
  • 规定post信息长度不能大于300字符

在validation文件夹下新建post.js,作为评论格式的验证文件

const Validator = require('validator');
const isEmpty = require("./empty");

module.exports = function validatePostInput(data) {
    let errors = {};

    //如果输入空(没有输入),需要将其改为空字符串
    data.text = !isEmpty(data.text) ? data.text : '';

    // 长度限制
    if (!Validator.isLength(data.text, { min: 2, max: 300 })) {
        errors.text = "text的长度不能小于2位并且不能大于300位!";
    }

    // 评论文本text不能为空
    if (Validator.isEmpty(data.text)) {
        errors.text = "text不能为空";
    }

    return {
        errors,
        isValid: isEmpty(errors)
    }
}

使用验证

在路由文件post.js中引入验证:

// 引入验证文件
const validatePostInput = require("../../validation/post");

在评论接口中使用验证:

// 验证数据格式
const { errors, isValid } = validatePostInput(req.body);
if (!isValid) {
    return res.status(400).json({ errors })
}

在这里插入图片描述

postman测试

记得在Header加上未过期的token
当我没有写text但提交时(post字符不能少于2字符的验证与此类似,此处不列举)
在这里插入图片描述

正确提交:
在这里插入图片描述


此时查看数据库,可以看到,多了一个posts表,里面有刚刚提交的评论信息,刚刚提交时用的是test账号的token,因此user值是该账号的id

在这里插入图片描述

获取post信息

获取所有post信息

  • 获取所有post信息并按时间降序排序,最新post信息在最前面
  • 不需要绑定user,因此没有使用token认证

路由文件post.js中编写接口:

//$route GET api/posts
//@desc 获取所有post信息
//@access public
router.get('/', (req, res) => {
    Posts.find()
        .sort({date:-1})
        .then(posts=>res.json(posts))
        .catch(err=>res.status(404).json({noposts:"找不到该信息"}))
})

postman测试:
为了体现按时间顺序排序,我多send了一条post信息上去
在这里插入图片描述

获取单条post

  • 根据post_id获取post
//$route GET api/posts/:po_id
//@desc 获取单条post
//@access public
router.get('/:po_id', (req, res) => {
    Posts.findById(req.params.po_id)
        .then(post=>res.json(post))
        .catch(err=>res.status(404).json({noposts:"找不到该post信息"}))
})

postman测试:

在这里插入图片描述

删除单条post信息

功能描述:

  • 根据用户提供的post_id删除该条post
  • 用户只能删除自己的post

逻辑思考:

  1. 根据token可以获得当前用户id,
  2. 如果该条post的用户id与当前用户id一致,就可以删除该post信息
//$route DELETE api/posts/:po_id
//@desc 删除单条post
//@access private
router.delete("/:po_id", passport.authenticate("jwt", { session: false }), (req, res) => {
    // 用户只能删除自己的post,若该post存在,则执行删除操作
    Posts.findById(req.params.po_id)
        .then(post => {
            if (post.user.toString() !== profile.user.toString()) {
                return res.status(401).json({ notAuthented: "您没有权限删除该信息" })
            }
            post.remove().then(()=>res.json({success:true}))
        })
            .catch(err=>res.status(404).json({fail:"信息删除失败"}))
})

postman测试:

本来有这两条post,都是账号test的:
在这里插入图片描述
我用账号test2去删除其中一条post(即执行删除操作时使用test2的token),提示没有删除权限:

在这里插入图片描述
换成用账号test去删除这条post(即执行删除操作时使用test的token),删除成功:
在这里插入图片描述

再次查看,已经没有那条id尾号88ba的post了:

在这里插入图片描述
注:login登录时会返回一个token,不同的用户登录有不同的token,此处用的是JWT的token,具体可以看之前的文章:《Node-express项目–个人简历:添加token认证》,谢谢支持


点赞接口

创建点赞

功能描述:

  • 此处点赞和取消赞是两个不同的接口,此处只实现点赞功能
  • 用户点赞需要是登录状态,该接口需要token认证
  • 如果没有被该用户赞过,就执行点赞操作
  • 如果该用户已经赞过,提示已经点过赞了
//$route POST api/posts/like/:po_id
//@desc 点赞
//@access private
router.post("/like/:po_id", passport.authenticate("jwt", { session: false }), (req, res) => {
	// 根据用户传入的id寻找评论post
     Posts.findById(req.params.po_id)
         .then(post => {
         
             // 查看该评论的likes是否已经有该用户
             if(post.likes.filter(like=>like.user.toString() === req.user.id).length > 0){
                 return res.status(400).json({haveLiked:"该用户已经点赞过"})
             }
             // 如果没有该用户,将用户id填入likes字段
             post.likes.unshift({user:req.user.id});
             // 保存至数据库
             post.save().then(post=>res.status(200).json(post))
             
         })
         .catch(err=>res.status(404).json({fail:"点赞失败"}))

})

postman测试:
一开始likes字段里都没有内容:
在这里插入图片描述
我们用test的账号发送点赞请求(带上未过期的test账号的token),被点赞的post id为60dad3df2c58a95e14429627:
在这里插入图片描述

取消点赞

功能描述:

  • 此处点赞和取消赞是两个不同的接口,此处只实现取消点赞功能
  • 用户只能取消自己点过的赞,其他人点的赞无法取消
  • 如果没有被该用户赞过,就提示还未点赞
  • 如果该用户已经赞过,就执行取消点赞操作
//$route POST api/posts/cancleLike/:po_id
//@desc 取消点赞
//@access private
router.post("/cancleLike/:po_id", passport.authenticate("jwt", { session: false }), (req, res) => {
	// 根据输入的评论id查找该评论
    Posts.findById(req.params.po_id)
        .then(post => {
        
            // 查看该评论的likes是否已经有该用户
            if (post.likes.filter(like => like.user.toString() === req.user.id).length === 0) {
                return res.status(400).json({ haveLiked: "该用户还未点赞过" })
            }
            // 寻找该用户在likes字段中的索引值
            const removeIndex = post.likes.map(like => like.user.toString()).indexOf(req.user.id);
            // 删除该用户点赞记录
            post.likes.splice(removeIndex, 1);
            // 保存至数据库
            post.save().then(post => res.status(200).json(post))

        })
        .catch(err => res.status(404).json({ fail: "取消点赞失败" }))


})

postman测试:
取消点赞前数据库查看:
在这里插入图片描述
取消点赞:
在这里插入图片描述

评论接口

创建评论

功能描述:

  • 根据用户输入的post id,决定评论的是哪条post
  • 用户登录的状态下才能评论,需要使用token验证身份
  • 评论必须有文本,即text不能为空
  • 将最新评论呈现在最前面
  • 保存到数据库
//$route POST api/posts/comment/:po_id
//@desc 评论
//@access private
router.post("/comment/:po_id", passport.authenticate("jwt", { session: false }), (req, res) => {

    // 验证数据格式
    const { errors, isValid } = validatePostInput(req.body);
    if (!isValid) {
        return res.status(400).json({ errors })
    }

    Posts.findById(req.params.po_id)
        .then(post => {
            const newCom = {
                user:req.user.id,
                text:req.body.text,
                name:req.body.name,
                avatar:req.body.avatar
            }
            post.comments.unshift(newCom);
            post.save()
                .then(post=>res.json(post))

        })
        .catch(err => res.status(404).json({ fail: "评论失败" }))

})

postman测试:
在这里插入图片描述

取消评论

功能描述:

  • 用户需要删除某条post信息下的某条评论
  • 需要输入post的id和评论的id
  • 在用户登录状态下才能删除,且只能删除自己提交的评论
  • 默认评论id(即comment_id)是存在的
//$route DELETE api/posts/cancleComment/:po_id
//@desc 删除评论
//@access private
router.delete("/cancleComment/:po_id/:comment_id", passport.authenticate("jwt", { session: false }), (req, res) => {

    Posts.findById(req.params.po_id)
        .then(post => {

            // 查看该评论是否是当前用户评论的,如果不是,则没有权限删除
            if (post.comments.filter(comment =>
               ( (comment._id == req.params.comment_id)) && (comment.user.toString() === req.user.id) )
                .length === 0) {
                return res.status(400).json({ failed: "您没有权限删除该条评论" })
            }
            // 寻找该用户在comments字段中的索引值
            const removeIndex = post.comments.map(comment => comment._id)以上是关于Node-express项目--个人简历:搭建posts接口并实现评论点赞以及相关功能的主要内容,如果未能解决你的问题,请参考以下文章

Node-express项目--个人简历:搭建当前用户的个人信息接口Profile

Node-express项目--个人简历:搭建posts接口并实现评论点赞以及相关功能

Node-express项目--个人简历:搭建posts接口并实现评论点赞以及相关功能

Node-express项目--个人简历:register(注册)接口编写记录

Node-express项目--个人简历:login(登录)接口编写记录

Node-express项目--个人简历:添加token认证