You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效搭建双版本共存的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 14:20:31