如何高效搭建双版本共存的Node Express RESTful API文件结构
最优API版本管理方案(Node.js + Express)
需求回顾
- 技术栈:Node.js + Express RESTful API
- 核心目标:同一服务器上同时运行v1、v2两个版本的API
- 项目分层要求:需包含router、controller、service、model文件夹
现有方案分析
方案1:版本独立目录结构
--src --v1 --router --controller --service --v2 --router --controller --service --db --config
- 优势:结构直白,版本之间完全隔离,不会互相干扰
- 问题:重复代码太多,比如两个版本的基础查询、创建逻辑几乎一致,维护成本高,改一处要同步改两个版本
方案2:继承式复用结构
--src --router --controller --user.js --user_v2.js // 继承user.js并重写方法 --service --user.js --user_v2.js --model --db --config
- 优势:能最大化复用v1代码,只改需要变更的部分
- 问题:版本迭代几次后,同目录下会堆一堆
xxx_v2、xxx_v3的文件,结构混乱,找对应版本的代码要翻半天
最优方案:混合式版本结构
兼顾代码复用和版本清晰度,把通用逻辑抽离+版本专属代码独立存放结合起来,文件结构如下:
--src --common # 所有版本共用的核心模块 --service --baseUserService.js # v1、v2通用的基础服务逻辑 --model --userModel.js --db --config --v1 --router --userRouter.js --controller --userController.js --service --userService.js # 继承base服务,只保留v1专属逻辑 --v2 --router --userRouter.js --controller --userController.js --service --userService.js # 继承base服务,重写/新增v2专属逻辑
具体实现示例
通用基础服务(common/service/baseUserService.js)
把两个版本都用到的逻辑放在这里,比如通用的查询、基础创建逻辑:
class BaseUserService { async getUserById(id) { // 通用的用户查询逻辑 return await userModel.findById(id); } async createUser(data) { // 通用的用户创建逻辑 return await userModel.create(data); } } module.exports = BaseUserService;
v1专属服务(v1/service/userService.js)
v1不需要改通用逻辑,直接继承基础服务就行:
const BaseUserService = require('../../common/service/baseUserService'); class UserServiceV1 extends BaseUserService { // 不需要额外修改,直接复用父类方法 } module.exports = UserServiceV1;
v2专属服务(v2/service/userService.js)
如果v2需要修改创建用户的逻辑,只重写对应的方法,其余逻辑复用:
const BaseUserService = require('../../common/service/baseUserService'); class UserServiceV2 extends BaseUserService { async createUser(data) { // v2专属逻辑:给用户默认添加active状态 data.status = data.status || 'active'; // 调用父类的通用创建逻辑 return await super.createUser(data); } } module.exports = UserServiceV2;
路由挂载(app.js)
在入口文件里分别挂载两个版本的路由,实现同一服务器运行:
const express = require('express'); const app = express(); const v1UserRouter = require('./src/v1/router/userRouter'); const v2UserRouter = require('./src/v2/router/userRouter'); app.use('/api/v1', v1UserRouter); app.use('/api/v2', v2UserRouter); app.listen(3000, () => { console.log('Server running on port 3000'); });
方案优势
- 复用性高:通用逻辑只写一次,各版本只维护专属变更的部分,减少重复代码
- 结构清晰:每个版本的router、controller、专属service都单独放在对应目录,版本边界明确,找代码一目了然
- 维护简单:修改某一版本的代码不会影响其他版本,新增v3版本时直接复制v2目录,改专属逻辑就行
- 扩展性强:后续可以灵活调整通用模块,或者给某个版本单独加新功能,不会牵一发而动全身
内容的提问来源于stack exchange,提问作者feeco
相关产品推荐
相关产品推荐

