如何在 Node/Express 应用程序中处理 api 版本

Posted

技术标签:

【中文标题】如何在 Node/Express 应用程序中处理 api 版本【英文标题】:How do you handle api version in a Node/Express app 【发布时间】:2014-11-20 07:54:46 【问题描述】:

我对 Node.js 很陌生,我面临以下问题。

我的中间件从链接api/v1/login 和一堆端点开始。 然后api/v1.1 又引入了 2 个端点。 api/v1.2 现在是最后一个并且有一些新的端点。

我应该如何有效地处理这个 api 版本控制?您如何使某个版本的端点也可用于下一个版本?

【问题讨论】:

是的。 /users 或 /users/lists 都是我所说的端点的例子 【参考方案1】:

首先,如果您正在构建 REST API 并且刚刚开始,您可能需要考虑使用 Restify 而不是 Express。虽然 Express 当然可以用于此目的,但 Restify 的设计符合 REST API 服务器的所有要求:标准化异常、API 版本控制等。

因此,我相信您的第一个问题是设计缺陷。仅当新 API 与先前版本向后兼容时,即当主要版本增加时(例如从 v1 到 v2),您才应该创建单独的端点。这应该尽可能少发生! 如果您只是添加新功能或进行其他不破坏现有代码的调整,那么您不应该创建不同的端点。因此,您不应该为 v1.1、v1.2 等创建端点,前提是所有适用于 v1.0 的代码也适用于 v1.1(如果不是这种情况,那么您将引入更改不向后兼容,因此您应该考虑将版本更改为 v2)。 请注意,每次您引入向后不兼容的更改时,您的所有用户都需要更新他们的代码,并且您必须支持旧 API 一段足以让所有用户更新的时间。对于您(您需要维护旧代码库)和您的用户(他们需要更新他们的代码)来说,这是一个昂贵的过程,因此应该尽可能少地发生。此外,对于每个版本,您都需要编写文档、创建示例等。(底线:花费大量时间来设计您的 API 服务器,因此它可能会持续下去,而无需为尽可能长)

为了回答您的问题,一种方法可以是为每个 API 集(每个版本)创建子文件夹,然后相应地设置路由器。例如,您的项目将如下所示:

/
-- app.js
-- routes/
-- -- v1/
-- -- -- auth.js
-- -- -- list.js
-- -- v2/
-- -- -- auth.js
-- -- -- list.js

这应该不是问题:由于 v2 与 v1 不向后兼容,因此这两个文件很可能有很大不同。 然后,在 Express 上相应地使用路由器。例如:

app.get('/v1/list/:id', v1.list)
app.all('/v1/auth', v1.auth)

app.get('/v2/list/:id', v2.list)
app.all('/v2/auth', v2.auth)

不过,还有其他选择。例如,一个更优雅(虽然稍微高级)的解决方案可以是:http://j-query.blogspot.ca/2013/01/versioned-apis-with-express.html

注意这个方法

虽然根据 semver,如果您计划在 v1 和 v2 之间实现许多实质性差异(几乎不可能重用代码),那么每个向后不兼容的更改都应该会增加 API 的主要版本,那么这种方法不适合你。

在最后一种情况下,您可能希望为 v1 和 v2 创建两个单独的 Node.js 应用程序,然后使用 nginx 配置正确的路由。版本控制不会在应用程序级别完成(每个应用程序将响应 '/auth'、'/list/:id' 而不是 '/v1/auth'、'/v1/list:id' 等),但 nginx会将前缀为“/v1/”的请求转发到一个工作服务器,将前缀为“/v2/”的请求转发到另一台。

【讨论】:

确实,我创建 API 的新版本只是因为我添加了新功能,而这正是造成混乱的原因。我添加的所有更改都是向后兼容的,因此根据我的阅读,在这种情况下添加新版本是不必要的。 如果我遵循您的概念,那么我的结构将来会如下所示:/ -- controllers/ ---- v1/ ---- v2/ -- helpers/ ---- v1/ ---- v2/ -- middlewares/ ---- v2/ -- models/ ---- v1/ ---- v2/ @user1791139 你不想那样做。有关在这种情况下您可以做什么的想法,请参阅我的更新答案。 如果我在这里复制所有这些文件并且没有这会产生很多重复。考虑一下这种情况,如果我在 v1 api (假设是 auth 模型)中有一个小的变化,并且需要在 v2 中反映 v1 中的所有现有内容。有没有其他方法可以处理这个 你把控制器和服务放在哪里?是在 v1 文件夹里面还是外面【参考方案2】:

像 restify 这样的框架更适合 api 版本控制,但是如果你使用 express 并且需要一个轻量级模块来版本你的路由,试试这个 npm 模块https://www.npmjs.com/package/express-routes-versioning

模块允许单独对各个路由进行版本控制。它支持服务器上的基本 semver 版本控制以匹配多个版本。 (如果需要的话)。它与特定的版本控制策略无关,并允许应用程序设置版本。

示例代码

var app = require('express')();
var versionRoutes = require('express-routes-versioning')();
app.listen(3000);
app.use(function(req, res, next) 
    //req.version is used to determine the version
   req.version = req.headers['accept-version'];
   next();
);
app.get('/users', versionRoutes(
   "1.0.0": respondV1,
   "~2.2.1": respondV2
));

// curl -s -H 'accept-version: 1.0.0' localhost:3000/users
// version 1.0.0 or 1.0 or 1 !
function respondV1(req, res, next) 
   res.status(200).send('ok v1');


//curl -s -H 'accept-version: 2.2.0' localhost:3000/users
//Anything from 2.2.0 to 2.2.9
function respondV2(req, res, next) 
   res.status(200).send('ok v2');

【讨论】:

【参考方案3】:

我猜你的 API 违反了 REST 约束,至少肯定违反了无状态约束。检查 REST 的统一接口约束。它告诉您如何将客户端与 API 的实现分离。完成此操作后,您可能不再需要版本控制。

如果您不想应用 REST 约束,那么我认为 URL 应该只包含主要版本号(以指示非向后兼容的更改)。之后,您可以定义供应商特定的 MIME 类型或内容类型参数,如果需要,您可以在其中描述次要、审查和构建版本号。因此,您的客户端应该发送带有这些版本参数的接受和内容类型标头。

顺便提一下,如果你想同时支持多个版本,你必须为每个版本编写文档。

【讨论】:

以上是关于如何在 Node/Express 应用程序中处理 api 版本的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Node Express 路由处理 React Router

在 Node/Express 的异步函数中捕获错误

使用node express generator配置socket.io

如何在 Heroku Node Express 应用程序中使用 LetsEncrypt SSL 证书?

使用 node express 生成器配置 socket.io

在 WebStorm 中配置端口 - React + Node Express 应用程序