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

后端 未结 3 1449
长情又很酷
长情又很酷 2021-01-30 05:16

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

相关标签:
3条回答
  • 2021-01-30 05:54

    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.

    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.

    Just to mention, if you want to support multiple versions at once, you have to write documentation for each of them.

    0 讨论(0)
  • 2021-01-30 06:05

    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');
    }
    
    0 讨论(0)
  • 2021-01-30 06:19

    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.

    0 讨论(0)
提交回复
热议问题