node.js 你如何处理 Node/Express 应用程序中的 api 版本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26040329/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you handle api version in a Node/Express app
提问by Paolo.nl
I am pretty new to Node.js and I am facing the following issue.
我对 Node.js 很陌生,我面临以下问题。
My middleware started with the link api/v1/loginand a bunch of endpoints.
Then api/v1.1introduced 2 more endpoints. api/v1.2is now the last and got some new endpoints.
我的中间件从链接api/v1/login和一堆端点开始。然后又api/v1.1引入了 2 个端点。api/v1.2现在是最后一个并获得了一些新的端点。
How shall I handle this api versioning in an efficient way? How do you make endpoints from a version available to the next versions as well?
我应该如何以有效的方式处理这个 api 版本控制?您如何使一个版本的端点也可用于下一个版本?
回答by ItalyPaleAle
First of all, if you are building a REST API and you have just started, you may want to consider using Restifyinstead of Express. While Express can certainly be used for this purpose, Restify has been designed with all the requirements for a REST API server: standardized exceptions, API versioning, etc.
首先,如果您正在构建 REST API 并且您刚刚开始,您可能需要考虑使用Restify而不是 Express。虽然 Express 当然可以用于此目的,但 Restify 的设计符合 REST API 服务器的所有要求:标准化异常、API 版本控制等。
Thus said, I believe your first problem is a design flaw. You should create separate endpoints only when the new APIs are notbackward-compatible with the previous version, i.e. when the major version is increased (for example from v1 to v2). This should happen as infrequently as possible!
If you are only adding new features or making other tweaks that do not break existing code, then you should not create a different endpoint. So, you should not create endpoints for v1.1, v1.2, etc, providing that all the code that works with v1.0 will also work with v1.1 (if that's not the case, then you're introducing changes that are not backward-compatible, and thus you should consider changing the version to v2).
Note that every time that you introduce backward-incompatible changes all your users will need to update their code, and you will have to support the old APIs for a period of time sufficient to let all your users update. This is an expensive process, for you (you need to maintain old codebases) and your users as well (they need to update their code), and thus should happen as infrequently as possible. Additionally, for each version you need to write documentation, create examples, etc.
(Bottom line: spend a lotof time designing your API server so it will likely last without backward-incompatible changes for as long as possible)
因此,我相信您的第一个问题是设计缺陷。仅当新 API与以前的版本不向后兼容时,即当主要版本增加(例如从 v1 到 v2)时,您才应该创建单独的端点。这种情况应该尽可能少发生!
如果您只是添加新功能或进行其他不会破坏现有代码的调整,则不应创建不同的端点。因此,您不应该为 v1.1、v1.2 等创建端点,前提是所有适用于 v1.0 的代码也适用于 v1.1(如果不是这种情况,那么您正在引入更改不向后兼容,因此您应该考虑将版本更改为 v2)。
请注意,每次您引入向后不兼容的更改时,您的所有用户都需要更新他们的代码,并且您必须在足够长的时间内支持旧 API,以让您的所有用户都更新。对于您(您需要维护旧的代码库)和您的用户(他们需要更新他们的代码)来说,这是一个昂贵的过程,因此应该尽可能少发生。此外,对于每个版本,您都需要编写文档、创建示例等。
(底线:花费大量时间设计您的 API 服务器,以便尽可能长时间地保持不向后兼容的更改)
To answer your question, then, a way to do that could be creating subfolders for each API set (each version), and then set the router accordingly. For example, your project will look like:
为了回答您的问题,一种方法是为每个 API 集(每个版本)创建子文件夹,然后相应地设置路由器。例如,您的项目将如下所示:
/
-- app.js
-- routes/
-- -- v1/
-- -- -- auth.js
-- -- -- list.js
-- -- v2/
-- -- -- auth.js
-- -- -- list.js
That should not be a problem: since v2 is not backward-compatible with v1, chances are that the two files are quite a lot different.
Then, on Express just use the router accordingly. For example:
这应该不是问题:由于 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)
There are other options, however. For example, a more elegant (though slightly advanced) solution can be: http://j-query.blogspot.ca/2013/01/versioned-apis-with-express.html
但是,还有其他选择。例如,一个更优雅(虽然稍微高级)的解决方案可以是:http: //j-query.blogspot.ca/2013/01/versioned-apis-with-express.html
Note on this method
注意这个方法
While, as per semver, every backward-incompatible change should see an increase in the major version of the APIs, if you plan to implement many and substantial differences between v1 and v2 (with very little possibility to re-use code), then this approach is not for you.
虽然,根据 semver,每个向后不兼容的更改都应该看到 API 主要版本的增加,如果您计划实现 v1 和 v2 之间的许多实质性差异(重用代码的可能性很小),那么这方法不适合你。
In this last case, you may want to create two separate Node.js apps for v1 and v2, and then configure the proper routing using nginx. Versioning will not be done at the app level (each app will respond to '/auth', '/list/:id' and NOT '/v1/auth', '/v1/list:id', etc), but nginx will forward requests with prefix '/v1/' to one worker server, and those with prefix '/v2/' to the other.
在最后一种情况下,您可能希望为 v1 和 v2 创建两个单独的 Node.js 应用程序,然后使用 nginx 配置正确的路由。不会在应用级别进行版本控制(每个应用都会响应“/auth”、“/list/:id”而不是“/v1/auth”、“/v1/list:id”等),而是 nginx会将带有前缀“/v1/”的请求转发到一个工作服务器,将带有前缀“/v2/”的请求转发到另一个。
回答by prasanna ramanujam
Frameworks like restify are better suited for api versioning, but if you are using express and need a lightweight module to version your routes, try this npm module https://www.npmjs.com/package/express-routes-versioning
像 restify 这样的框架更适合 api 版本控制,但是如果您使用 express 并且需要一个轻量级模块来版本您的路由,请尝试使用这个 npm 模块https://www.npmjs.com/package/express-routes-versioning
Module allows individual routes to be versioned separately. It supports basic semver versioning on the server to match multiple versions. (if needed). It is agnostic about specific versioning strategies and allows the application to set the version.
模块允许单独对各个路由进行版本控制。它支持服务器上的基本 semver 版本控制以匹配多个版本。(如果需要的话)。它与特定的版本控制策略无关,并允许应用程序设置版本。
Sample code
示例代码
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');
}
回答by inf3rno
I guess your API violates the REST constraints, at least the stateless constraint certainly. Check the uniform interface constraint of REST. It tells you how to decouple the clients from the implementation of the API. After you did that you probably won't need versioning anymore.
我猜你的 API 违反了 REST 约束,至少肯定是无状态约束。检查REST的统一接口约束。它告诉您如何将客户端与 API 的实现分离。在你这样做之后,你可能不再需要版本控制了。
If you don't want to apply REST constraints, then I think the URL should contain only the major version number (to indicate non-backward compatible changes). After that you can define vendor specific MIME types or content type parameters in which you can describe the minor, review and build version numbers if you want. So your clients should send accept and content-type headers with these version parameters.
如果您不想应用 REST 约束,那么我认为 URL 应仅包含主要版本号(以指示非向后兼容更改)。之后,您可以定义供应商特定的 MIME 类型或内容类型参数,如果需要,您可以在其中描述次要、和构建版本号。因此,您的客户端应该发送带有这些版本参数的接受和内容类型标头。
Just to mention, if you want to support multiple versions at once, you have to write documentation for each of them.
顺便提一下,如果您想一次支持多个版本,则必须为每个版本编写文档。

