Windows Azure Websites and nodejs - the Setup

Let's go thru the step by step guide to setup the Windows Azure WebSites (WAWS) for a node.js project. You have likely seen the WebSites documentation and know it is very, very easy. Yes, it is, but you won't get node.js 0.10.13 by default, you won't get newest npm etc. Also I would like to use SQL Database which is also not very easy.

Before you start

I assume you have created the WAWS in 32-bit mode (64-bit setup is similar but not available in free tier) and you have SQL Database set up (20 MB free one is fine). I also assume you have git setup for the project (may be local git or from Github/Bitbucket).

First check

First thing to do before we begin the proper setup is to commit file server.js with below content to just check if all is working fine:

var http = require('http')
var port = process.env.PORT || 8080;
http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end(process.version);
}).listen(port);

After commiting and pushing check if you will see the node.js version number after using website URL in the browser. It should be v0.6.20, as this is the default version available in WAWS.

Getting newer node.js and npm

Create package.json file using npm init command. WAWS has more than one version of node.js available and it selects the proper one using engines, but at the moment it does not support 0.10.x.

Luckily Gleen Block created a small script that automates installing a newer version straight in the WAWS (including npm), but it is the best to specify exact versions of node.js and npm.

Use the description provided on Github and copy necessary files to your repository (.deployment, conf.js and deploy.sh).

Add below to package.json:

"engines": {
    "node": "0.10.13",
    "npm": "1.3.2"
}

Start the git deployment. It will take much more time than usual, but it is because it must download a lot of things. When it will complete refresh your WebSite URL and you should see v0.10.13. Nice!

SQL Database

Let's assume that our application will use Azure SQL Database. I explain how to get MS SQL ODBC driver working which is not easy. An alternative is to use tedious. Tt is a pure JavaScript implementation (which in oppose to the name is far less tedious to set up). It is also best to look at the additional connection pooling for tedious. ODBC driver has the connection pooling build in.

MS SQL Driver setup requires installing additional node.js module (node-sqlserver). The bad thing is this is a native module, so just using npm install node-sqlserver is not enough with node.js 0.10.x (there are precompiled versions available from Microsoft that will be installed automatically but only on node.js 0.6 and 0.8; they are available as MSI packages on MS Dowload Page).

Clone the node-sqlserver repository. The current code in repo is not compatible with the 0.10.x because of small change in node API. We have to fix it first. Find the src/Operation.h file and change the line:

int result = uv_queue_work(uv_default_loop(), &operation->work, OnBackground, OnForeground);

to line:

int result = uv_queue_work(uv_default_loop(), &operation->work, OnBackground, (uv_after_work_cb)OnForeground);

Prepare the environment for compilation as explained on Github page (there is a lot of it). You can use VS Express 2012(2013) instead od 2010.

There is one additional fix required. Find the file building.gyp in the cloned repo and add below entry after include_dirs array:

'libraries': [
    'odbc32.lib'
],

Now run the VS command line tool (the standard cmd may not work), go to the cloned repository and run the below commands:

node-gyp configure
node-gyp build

In build/Release folder there should be file sqlserver.node now. Copy it to lib folder from repo and you can now remove the whole build dir.

Create in your own project _nodemodules folder and in it the msnodesql folder. To this folder copy package.json from driver's repo and also the whole lib folder as it is.

The structure in msnodesql should be like below:

│   package.json
│
└───lib
        sql.js
        sqlserver.native.js
        sqlserver.node

What is important that the whole recompilation is needed only between major node.js releases, so if there will be update to node.js 0.10.22 or similar you don't have to do anything.

Last steps

In WAWS the npm can install all necessary module dependencies so they don't have to have them in the git repository. But modules with native code cannot be compiled. It is easy to just create special .gitignore entries to push them to the repository.

Create .gitignore file with below content:

config.json
!node_modules/
node_modules/*
!node_modules/msnodesql

This way we can easily use package.json for everything except SQL driver. I'll explain a config.json addition in a moment.

Last step will be to modify package.json by adding two dependencies (one we already know). The exact version for msnodesql must match the one in module itself so npm will not try to update it. The other one is nconf, which is nice configuration helper. We will use it to read configuration settings from environment (used in WAWS) but if not be set there we will use settings from config.json (file will be used only for local development and not be commited).

Add below to global package.json:

"dependencies": {
    "nconf": "0.6.7",
    "msnodesql": "0.2.1"
}

and run command:

npm install

Final code to test the setup

We are almost ready to test everything locally and on WAWS. Change the code from server.js to below code:

var http = require('http');
var mssql = require('msnodesql');
var nconf = require('nconf');

// Get env and with smaller priority from config.json
nconf.env().file({ file: 'config.json' });

var conn = nconf.get("SQLAZURECONNSTR_DB1");
var port = nconf.get("PORT");

http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.write(process.version);

    // Change the query to the proper one from your DB!
    mssql.query(conn, 'SELECT TOP (1) * FROM gluwer.test123;', function(err, results) {
        if (err) {
            res.end(JSON.stringify(err));
        } else {
            res.end(JSON.stringify(results));
        }
    });

}).listen(port);

Create config.json file locally and add to it below content:

{
    "SQLAZURECONNSTR_DB1": "Driver={SQL Server Native Client 11.0};***copy from Azure Management Portal from ODBC connection string***",
    "PORT": 8080
}

Please note one important change! The Driver param must be set to SQL Server Native Client 11.0 locally, but to SQL Server Native Client 10.0 on Azure, as Azure uses older ODBC client. Also don't forget to add your local IP to Azure SQL Database firewall.

Everything is ready to be tested locally, so start server.js. You should see something like:

v0.10.13[{"id":1,"test":"Just testing"}]

If you see sqlstate there, it means there was some kind of SQL error.

Commit the changed files, but do not yet deploy. Add DB connection string to WAWS in Management Portal. As a name use DB1 (prefix is added automatically by Azure). Deploy the code to Azure. Check the URL of your application in the browser. You should see exactly the same content as when run locally.

Summary

It wasn't easy, I agree, but now you have everything set up with newest node, npm and MS SQL Driver. What is important you can easily save this project as a template if you plan to create more projects.

Comments