如何扩展Express-Mongoose-ES6-REST-API:添加新模块完整指南

【免费下载链接】express-mongoose-es6-rest-api :collision: A boilerplate application for building RESTful APIs Microservice in Node.js using express and mongoose in ES6 with code coverage and JsonWebToken Authentication 【免费下载链接】express-mongoose-es6-rest-api 项目地址: https://gitcode.com/gh_mirrors/ex/express-mongoose-es6-rest-api

Express-Mongoose-ES6-REST-API是一个基于Node.js的RESTful API微服务开发框架,它结合了Express和Mongoose的强大功能,并采用ES6语法编写,提供了代码覆盖率和JsonWebToken身份验证功能。本指南将详细介绍如何为这个框架添加新模块,帮助开发者快速扩展项目功能。

1. 理解项目结构

在开始添加新模块之前,首先需要了解Express-Mongoose-ES6-REST-API的项目结构。主要目录和文件如下:

  • config/: 包含配置文件,如config.jsexpress.js
  • server/: 应用程序的主要代码目录
    • auth/: 身份验证相关代码
    • helpers/: 辅助工具和类,如APIError.js
    • tests/: 测试文件
    • user/: 用户模块相关代码

每个功能模块通常包含以下文件:

  • [module].model.js: 数据模型定义
  • [module].controller.js: 业务逻辑处理
  • [module].route.js: 路由定义
  • [module].test.js: 单元测试

2. 创建新模块的步骤

2.1 创建模型文件

首先,我们需要创建一个新的模型文件。模型定义了数据结构和数据库交互方法。以创建一个"Post"模块为例,在server/post/目录下创建post.model.js文件:

const Promise = require('bluebird');
const mongoose = require('mongoose');
const httpStatus = require('http-status');
const APIError = require('../helpers/APIError');

/**
 * Post Schema
 */
const PostSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  content: {
    type: String,
    required: true
  },
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  createdAt: {
    type: Date,
    default: Date.now
  }
});

/**
 * Statics
 */
PostSchema.statics = {
  /**
   * Get post
   * @param {ObjectId} id - The objectId of post.
   * @returns {Promise<Post, APIError>}
   */
  get(id) {
    return this.findById(id)
      .exec()
      .then((post) => {
        if (post) {
          return post;
        }
        const err = new APIError('No such post exists!', httpStatus.NOT_FOUND);
        return Promise.reject(err);
      });
  },

  /**
   * List posts in descending order of 'createdAt' timestamp.
   * @param {number} skip - Number of posts to be skipped.
   * @param {number} limit - Limit number of posts to be returned.
   * @returns {Promise<Post[]>}
   */
  list({ skip = 0, limit = 50 } = {}) {
    return this.find()
      .sort({ createdAt: -1 })
      .skip(+skip)
      .limit(+limit)
      .exec();
  }
};

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

2.2 创建控制器文件

接下来,创建控制器文件post.controller.js,处理业务逻辑:

const Post = require('./post.model');

/**
 * Load post and append to req.
 */
function load(req, res, next, id) {
  Post.get(id)
    .then((post) => {
      req.post = post; // eslint-disable-line no-param-reassign
      return next();
    })
    .catch(e => next(e));
}

/**
 * Get post
 * @returns {Post}
 */
function get(req, res) {
  return res.json(req.post);
}

/**
 * Create new post
 * @property {string} req.body.title - The title of post.
 * @property {string} req.body.content - The content of post.
 * @property {string} req.body.author - The author of post.
 * @returns {Post}
 */
function create(req, res, next) {
  const post = new Post({
    title: req.body.title,
    content: req.body.content,
    author: req.body.author
  });

  post.save()
    .then(savedPost => res.json(savedPost))
    .catch(e => next(e));
}

/**
 * Update existing post
 * @property {string} req.body.title - The title of post.
 * @property {string} req.body.content - The content of post.
 * @returns {Post}
 */
function update(req, res, next) {
  const post = req.post;
  post.title = req.body.title;
  post.content = req.body.content;

  post.save()
    .then(savedPost => res.json(savedPost))
    .catch(e => next(e));
}

/**
 * Get post list.
 * @property {number} req.query.skip - Number of posts to be skipped.
 * @property {number} req.query.limit - Limit number of posts to be returned.
 * @returns {Post[]}
 */
function list(req, res, next) {
  const { limit = 50, skip = 0 } = req.query;
  Post.list({ limit, skip })
    .then(posts => res.json(posts))
    .catch(e => next(e));
}

/**
 * Delete post.
 * @returns {Post}
 */
function remove(req, res, next) {
  const post = req.post;
  post.remove()
    .then(deletedPost => res.json(deletedPost))
    .catch(e => next(e));
}

module.exports = { load, get, create, update, list, remove };

2.3 创建路由文件

然后,创建路由文件post.route.js,定义API端点:

const express = require('express');
const postCtrl = require('./post.controller');

const router = express.Router(); // eslint-disable-line new-cap

router.route('/')
  /** GET /api/posts - Get list of posts */
  .get(postCtrl.list)

  /** POST /api/posts - Create new post */
  .post(postCtrl.create);

router.route('/:postId')
  /** GET /api/posts/:postId - Get post */
  .get(postCtrl.get)

  /** PUT /api/posts/:postId - Update post */
  .put(postCtrl.update)

  /** DELETE /api/posts/:postId - Delete post */
  .delete(postCtrl.remove);

/** Load post when API with postId route parameter is hit */
router.param('postId', postCtrl.load);

module.exports = router;

2.4 注册新路由

最后,需要在主路由文件中注册新创建的路由。编辑index.route.js文件:

const express = require('express');
const userRoutes = require('./server/user/user.route');
const authRoutes = require('./server/auth/auth.route');
const postRoutes = require('./server/post/post.route'); // 导入新路由

const router = express.Router(); // eslint-disable-line new-cap

// TODO: use glob to match *.route files

/** GET /health-check - Check service health */
router.get('/health-check', (req, res) =>
  res.send('OK')
);

// mount user routes at /users
router.use('/users', userRoutes);

// mount auth routes at /auth
router.use('/auth', authRoutes);

// mount post routes at /posts  // 注册新路由
router.use('/posts', postRoutes);

module.exports = router;

3. 添加测试文件

为了确保新模块的功能正常,建议添加测试文件post.test.js

const request = require('supertest-as-promised');
const httpStatus = require('http-status');
const chai = require('chai');
const expect = chai.expect;
const app = require('../../index');

chai.config.includeStack = true;

describe('## Post API', () => {
  let post = {
    title: 'Test Post',
    content: 'This is a test post',
    author: '56c78793516564681e041791' // 替换为实际的用户ID
  };

  describe('# POST /api/posts', () => {
    it('should create a new post', (done) => {
      request(app)
        .post('/api/posts')
        .send(post)
        .expect(httpStatus.OK)
        .then((res) => {
          expect(res.body.title).to.equal(post.title);
          expect(res.body.content).to.equal(post.content);
          post = res.body;
          done();
        })
        .catch(done);
    });
  });

  describe('# GET /api/posts', () => {
    it('should get all posts', (done) => {
      request(app)
        .get('/api/posts')
        .expect(httpStatus.OK)
        .then((res) => {
          expect(res.body).to.be.an('array');
          done();
        })
        .catch(done);
    });
  });

  // 可以添加更多测试用例...
});

4. 验证新模块

完成以上步骤后,你可以通过以下步骤验证新模块是否正常工作:

  1. 启动应用程序:npm start
  2. 使用API测试工具(如Postman)发送请求到新创建的API端点:
    • POST /api/posts - 创建新文章
    • GET /api/posts - 获取所有文章
    • GET /api/posts/:postId - 获取特定文章
    • PUT /api/posts/:postId - 更新文章
    • DELETE /api/posts/:postId - 删除文章

5. 总结

通过以上步骤,你已经成功地为Express-Mongoose-ES6-REST-API框架添加了一个新的"Post"模块。这个过程可以应用于任何其他新模块的创建,只需按照相同的模式创建模型、控制器、路由和测试文件,并在主路由中注册新路由即可。

这种模块化的设计使得项目易于扩展和维护,每个功能模块都有清晰的职责划分,符合RESTful API的设计原则。希望本指南能帮助你更好地理解和使用Express-Mongoose-ES6-REST-API框架。

【免费下载链接】express-mongoose-es6-rest-api :collision: A boilerplate application for building RESTful APIs Microservice in Node.js using express and mongoose in ES6 with code coverage and JsonWebToken Authentication 【免费下载链接】express-mongoose-es6-rest-api 项目地址: https://gitcode.com/gh_mirrors/ex/express-mongoose-es6-rest-api

更多推荐