Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you handle api version in a Node/Express app

I am pretty new to Node.js and I am facing the following issue.

My middleware started with the link api/v1/login and a bunch of endpoints. Then api/v1.1 introduced 2 more endpoints. api/v1.2 is now the last and got some new endpoints.

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?

like image 989
Paolo.nl Avatar asked Sep 25 '14 13:09

Paolo.nl


2 Answers

First of all, if you are building a REST API and you have just started, you may want to consider using Restify instead 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.

Thus said, I believe your first problem is a design flaw. You should create separate endpoints only when the new APIs are not backward-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 lot of time designing your API server so it will likely last without backward-incompatible changes for as long as possible)

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:

/ -- 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:

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

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.

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.

like image 129
ItalyPaleAle Avatar answered Sep 28 '22 12:09

ItalyPaleAle


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

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.

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');
}
like image 34
prasanna ramanujam Avatar answered Sep 28 '22 11:09

prasanna ramanujam