Feb 14, 2018

API Versioning, Express Routers and Node.js

Do you want to set up an API versioning in Node.js and Express environment? This tutorial explains the different ways to do REST API versioning step by step. We will implement the following routing for the versioning:

GET /api/v1.0/

POST /api/v1.0/

GET /api/v2.0/

POST /api/v2.0/

Environment:

Node.js 8.15

NPM 6.4.1

Express 4.16

VSCode 1.29

Setup New Express Application

The easiest way to setup express application is to use express generator. Let’s run following command


npm install express-generator -g
express api-version-demo
cd api-version-demo
npm install
npm start

Now on your browser, http://localhost:3000 will show the default express page.

Setup VSCode

I am using Visual Studio Code editor. Let's set debugging for the app

Open the app in VSCode > Click Debug icon > Configure gear icon on the Debug view top bar > Select debug environment: Node.

It will generate a launch.json. Replace with following configurations:


{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceFolder}/bin/www",
            "runtimeVersion": "8.15.0"
        }
    ]
}

Replace runtimeVersion with your Node version. Put a breakpoint anywhere in app.js and debug the application.

in the Debug view > Select “Launch” in dropdown > F5 or click green arrow to start debug session.

Make sure breakpoint hits happens.

Setup Code

We are going to setup our express routing so remove following lines in app.js


var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

app.use('/', indexRouter);
app.use('/users', usersRouter);

and delete routes folder. We no longer need it.

Approach 1

Create the following directory structure in the application:


api
api/v1.0
api/v2.0
api versioning node.js express

add api/v1.0/index.js with following code:



var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
  res.send('Hello v1.0 GET API from TechBrij.com');
});

router.post('/', function(req, res, next) {
  res.send('Hello v1.0 POST API from TechBrij.com');
});

module.exports = router;

add api/v2.0/index.js with following code:


var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
  res.send('Hello v2.0 GET API from TechBrij.com');
});

router.post('/', function(req, res, next) {
  res.send('Hello v2.0 POST API from TechBrij.com');
});

module.exports = router;

Now add api/index.js with following content:


var express = require('express');
var router = express.Router();

router.use('/v1.0', require('./v1.0'));
router.use('/v2.0', require('./v2.0'));

module.exports = router;

When any new version is added, you need to create a new folder, setup routerfile and add a line in the above file.

Add following in app.js before 404 routing


app.use('/api', require('./api'));

Now run the application. I am using REST Client in Firefox, you can use Postman in Google Chrome.

api versioning node.js express

You will see for each version, the expected method is called.

Approach 2

As in approach 1, for each new version we need to add entry in api/index.js file, let's get this step done dynamically based on folder structure. As we are strictly following folder structure and index.js file is for express router, we can leverage it.

Let's keep the existing code separate. Copy the api folder, paste with api-new in application and delete api-new/index.js file. Add following code in app.js:


var fs=require("fs");

function processRoutePath(routePath, currentLevel, maxLevel){
  if (currentLevel > maxLevel){
    return;
  }
  else{
      fs.readdirSync(routePath).forEach(function(file) {
      var filepath = routePath + '/' + file;
      var stat= fs.statSync(filepath);
      if (stat.isDirectory()) {            
            processRoutePath(filepath, currentLevel+1, maxLevel);
      } else {
            console.info('File: ' + filepath +  ' route: '+ routePath + '\n');
            if (file == 'index.js'){
              app.use(routePath.substring(1), require(routePath));
            }            
        }    
  });
  }
}

var route="./api-new"; 
processRoutePath(route,0,1);

To get files from a folder in Node.js, read following post:

Node.js: Traversing A Directory Recursively with Limited Depth

I customized the code based on our requirement. processRoutePath method traverses the provided routePath and use index.js router. As we have to search express routers for sub-folder only, so pass maxLevel = 1.

Run the application, you will get following info on console:

api versioning node.js express

If you run the API with api-new i.e. http://localhost:3000/api-new/v1.0/, you will get the same result as in approach 1.

Source Code

The full source code is available on GitHub.

Conclusion

In this tutorial, we have setup a new express app, VSCode for debugging and REST API versioning using Express router in Node.js. Also, see a way to dynamically add routing from folder structure.

One way is to use route parameter for versioning and use the parameter in the middleware and perform action accordingly. But if same method is used for different versions with if/else conditions then it creates complexity. So I prefer different files for different versions so that different teams can work in parallel.

Do Let me know how you are implementing API versioning. Feel free to leave your thoughts in comment box.

Enjoy Node.js!!