博客项目全栈开发 API接口 第三章:文章CURD功能

前言

默认大家已经看过前面的文章,并成功完成前面步骤。这章主要写文章的CURD功能api的开发

文章功能

创建文章模型 models/post.js

const mongoose = require('mongoose');

const postSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
    trim: true
  },
  content: {
    type: String,
    required: true
  },
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  tags: [{
    type: String,
    trim: true
  }],
  category: {
    type: String,
    required: true,
    trim: true
  },
  status: {
    type: String,
    enum: ['draft', 'published'],
    default: 'draft'
  }
}, {
  timestamps: true
});

const Post = mongoose.model('Post', postSchema);
module.exports = Post;

创建文章控制器controllers/postController.js

const Post = require('../models/Post');

// 创建文章
const createPost = async (req, res) => {
  try {
    const { title, content, tags, category } = req.body;
    
    const post = await Post.create({
      title,
      content,
      tags,
      category,
      author: req.user._id
    });

    res.status(201).json(post);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

// 获取所有文章
const getPosts = async (req, res) => {
  try {
    const { page = 1, limit = 10, category, tag } = req.query;
    
    const query = {};
    if (category) query.category = category;
    if (tag) query.tags = tag;

    const posts = await Post.find(query)
      .populate('author', 'username')
      .sort({ createdAt: -1 })
      .limit(limit * 1)
      .skip((page - 1) * limit);

    const count = await Post.countDocuments(query);

    res.json({
      posts,
      totalPages: Math.ceil(count / limit),
      currentPage: page
    });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

// 获取单篇文章
const getPost = async (req, res) => {
  try {
    const post = await Post.findById(req.params.id)
      .populate('author', 'username');
    
    if (!post) {
      return res.status(404).json({ message: '文章不存在' });
    }

    res.json(post);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

// 更新文章
const updatePost = async (req, res) => {
  try {
    const { title, content, tags, category, status } = req.body;
    
    const post = await Post.findById(req.params.id);
    
    if (!post) {
      return res.status(404).json({ message: '文章不存在' });
    }

    // 检查是否是作者或管理员
    if (post.author.toString() !== req.user._id.toString() && req.user.role !== 'admin') {
      return res.status(403).json({ message: '没有权限修改此文章' });
    }

    const updatedPost = await Post.findByIdAndUpdate(
      req.params.id,
      { title, content, tags, category, status },
      { new: true }
    ).populate('author', 'username');

    res.json(updatedPost);
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

// 删除文章
const deletePost = async (req, res) => {
  try {
    const post = await Post.findById(req.params.id);
    
    if (!post) {
      return res.status(404).json({ message: '文章不存在' });
    }

    // 检查是否是作者或管理员
    if (post.author.toString() !== req.user._id.toString() && req.user.role !== 'admin') {
      return res.status(403).json({ message: '没有权限删除此文章' });
    }

    await post.deleteOne();
    res.json({ message: '文章已删除' });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

module.exports = {
  createPost,
  getPosts,
  getPost,
  updatePost,
  deletePost
};

创建文章路由routes/posts.js

const express = require('express');
const router = express.Router();
const { 
  createPost, 
  getPosts, 
  getPost, 
  updatePost, 
  deletePost 
} = require('../controllers/postController');
const { protect } = require('../middleware/auth');

// 获取所有文章
router.get('/', getPosts);

// 获取单篇文章
router.get('/:id', getPost);

// 创建文章(需要登录)
router.post('/', protect, createPost);

// 更新文章(需要登录)
router.put('/:id', protect, updatePost);

// 删除文章(需要登录)
router.delete('/:id', protect, deletePost);

module.exports = router;

app.js中添加文章路由

const postRoutes = require('./routes/posts');
app.use('/api/posts', postRoutes);

OK 写完了。现在系统应该支持

  • 文章创建
  • 获取文章列表(支持分页、分类和标签筛选)
  • 获取单篇文章
  • 更新文章
  • 删除文章
  • 权限控制(只有作者和管理员可以修改/删除文章)

测试:

POST http://localhost:3000/posts
Content-Type: application/json
{
    "title": "测试文章标题",
    "content": "这是测试文章的内容",
    "category": "技术",  // 添加必填的 category 字段
    "tags": "测试",  // 可选的 tags 字段
    "status": "draft"  // 可选的 status 字段,默认为 "draft"
}

返回下列信息,创建文章接口成功

{
    "title": "测试文章标题",
    "content": "这是测试文章的内容",
    "author": "68234d0c35c1531af74f8b21",
    "tags": [
        "测试"
    ],
    "category": "技术",
    "status": "draft",
    "_id": "6825e0d1ab18230b995814ca",
    "createdAt": "2025-05-15T12:40:49.553Z",
    "updatedAt": "2025-05-15T12:40:49.553Z",
    "__v": 0
}

其他接口不来发了,大家自己测试下把。记得对照下models/Post.js里的数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值