Deploying Node.js Applications to Iron Foundry using the Cloude9 IDE

This week, I attended the Cloud Foundry “one year anniversary” event where among other things, Cloud9 announced support for deployment to Cloud Foundry from their innovative Cloud9 IDE. The Cloud9 IDE lets you write HTML5, JavaScript and Node.js applications in an entirely web-based environment. Their IDE’s editor support many other programming languages, but they provide the fullest support for HTML/JavaScript. Up until this week, you could deploy your applications to Joyent, Heroku and Windows Azure. Now, you can also target any Cloud Foundry environment. Since I’ve been meaning to build a Node.js application, this seemed like the perfect push to do so. In this blog post, I’ll show you how to author a Node.js application in the Cloud9 IDE and push it to Iron Foundry’s distribution of Cloud Foundry. Iron Foundry recently announced their support for many languages besides .NET, so here’s a chance to see if that’s really the case.

Let’s get started. First, I signed up for a free Cloud9 IDE account. It was super easy. Once I got my account, I saw a simple dashboard that showed my projects and allowed me to connect my account to Github.

2012.04.12node01

From here, I can create a new project by clicking the “+” icon above My Projects.

2012.04.12node02

At this point, I was asked for the name of my project and type of project (Git/Mercurial/FTP). Once my SeroterNodeTest project was provisioned, I jumped into the Cloud9 IDE editor interface. I don’t have any files (except for some simple Git instructions in a README file) but I got my first look at the user interface.

2012.04.12node03

The Cloud9 IDE provides much more than just code authoring and syntax highlighting. The IDE lets me create files, pull in Github projects, run my app in their environment, deploy to a supported cloud environment, and perform testing/debugging of the app. Now I was ready to build the app!

I didn’t want to JUST build a simple “hello world” app, so I thought I’d use some recommended practices and let my app either return HTML or JSON based on querystring parameters. To start with, I’ll create my Node.js server by right-clicking my project and adding a new file named server.js.

2012.04.12node04

Before writing any code, I decided that I didn’t want to just build an HTML string by hand and have my Node.js app return it. So, I decided to use Mustache and separate my data from my HTML. Now, I couldn’t see an easy way to import this JavaScript library through the UI until I noticed that Cloud9 IDE supported the Node Package Manager (npm) in the exposed command window. From this command window, I could write a simple command (“npm install mustache”) and the necessary JavaScript libraries were added to my project.

2012.04.12node05

Great. Now I was ready to write my Node.js server code. First, I added a few references to required libraries.

//create some variables that reference key libraries
var http = require('http');
var url = require('url');
var Mustache = require('./node_modules/mustache/mustache.js');

Next, I created a handler function that writes out HTML when it gets invoked. This function takes a “response” object which represents the content being returned to the caller. Doing response writing at this level helps prevent blocking calls in Node.js.

//This function returns an HTML response when invoked
function getweb(response)
{
    console.log('getweb called');
    //create JSON object
    var data = {
        name: 'Richard',
        age: 35
    };

    //create template that formats the data
    var template = 'Hi there, <strong>{{ name }}</strong>';

    //use Mustache to apply the template and create HTML
    var result = Mustache.to_html(template, data);

    //write results back to caller
    response.writeHead(200, {'Content-Type': 'text/html'});
    response.write(result);
    response.end();
}

My second handler responds to a different URL querystring and returns a JSON object back to the caller.

//This function returns JSON to simulate a service call
function callservice(response)
{
    console.log('callservice called');
    //create JSON object
    var data = {
        name: 'Richard',
        age: 35
    };

    //write results back to caller
    response.writeHead(200, {'Content-Type': 'text/html'});
    //convert JSON to string
    response.write(JSON.stringify(data));
    response.end();
}

How do I choose which of these two handlers to call? I have a function that uses input parameters to dynamically invoke one function or the other, based on the querystring input.

//function that routes the request to appropriate handlers
function routeRequest(path, reqhandle, response)
{
    //does the request map to one of my function handlers?
     if (typeof reqhandle[path] === 'function') {
       //yes, so call the function
       reqhandle[path](response);
     }
     else
     {
         console.log('no match');
         response.end();
     }
}

The last function in my server.js file is the most important. This “startup” function is my entry point of the module. It starts the Node.js server and defines the operation that is called on each request. That operation invokes the previously defined routeRequest function which then explicitly handles the request.

//inital function that routes requests
function startup(reqhandle)
{
    //function that responds to client requests
    function onRequest(request, response)
    {
        //yank out the path from the URL the client hit
        var path = url.parse(request.url).pathname;

        //handle individual requests
        routeRequest(path, reqhandle, response);
    }

    //start up the Node.js server
    http.createServer(onRequest).listen(process.env.PORT);
    console.log('Server running');
}

Finally, at the bottom of this module, I expose the functions that I want other modules to be able to call.

//expose this module's operations so they can be called from main JS file
exports.startup = startup;
exports.getweb = getweb;
exports.callservice = callservice;

With my primary server done, I went and added a new file, index.js.

2012.04.12node06

This acts as my application entry point. Here I reference the server.js module and create an array of valid querystring values and which function should respond to which path.

//reference my server.js module
var server = require('./server');

//create an array of valid input values and what server function to invoke
var reqhandle = {};
reqhandle['/'] = server.getweb;
reqhandle['/web'] = server.getweb;
reqhandle['/service'] = server.callservice;

//call the startup function to get the server going
server.startup(reqhandle);

And … we’re done. I switched to the Run tab, made sure I was starting with index.js and clicked the Debug button. At the bottom of the screen, in the Console window, I could see whether or not the application was able to start up. If so, a URL is shown.

2012.04.12node07

Clicking that link took me to my application hosted by Cloud9.

2012.04.12node08

With no URL parameters (just “/”), the web function was called. If I add “/service” to the URL, I see a JSON result.

2012.04.12node09

Cool! Just to be thorough, I also threw the “/web” on the URL, and sure enough, my web function was called.

2012.04.12node10

I was now ready to deploy this bad boy to Iron Foundry. The Cloud9 IDE is going to look for a package.json file before allowing deployment, so I went ahead and added a very simple one.

2012.04.12node11

Also, Cloud Foundry uses a different environmental variable to allocate the server port that Node.js listens on.So, I switched this line:

http.createServer(onRequest).listen(process.env.C9_PORT);

to this …

http.createServer(onRequest).listen(process.env.VCAP_APP_PORT);

I moved to the Deployment tab and clicked on the “+” sign at the top.

2012.04.12node12

What comes up is a wizard where I chose to deploy to Cloud Foundry (but could have also chosen Windows Azure, Joyent or Heroku).

2012.04.12node13

The key phrasing there is that you are signing into a Cloud Foundry API. So ANY Cloud Foundry provider (that is accessible by Cloud9 IDE) is a valid target. I plugged in the API endpoint of the newest Iron Foundry environment, and provided my credentials.

2012.04.12node14

Once I signed in, I saw that I had no apps in this environment yet. After putting a name to application, I clicked the Create New Cloud Foundry application button and was given the choice of Node.js runtime version, number of instances to run this on, and how much RAM to allocate.

2012.04.12node15

That was the final step in the deployment target wizard, and now all that’s left to do is select this new package and click Deploy.

2012.04.12node16

In seven seconds, the deployment was done and I was provided my Iron Foundry URL.

2012.04.12node17

Sure enough, hitting that URL (http://seroternodetest.ironfoundry.me/service) in the browser resulted in my Node.js application returning the expected response.

2012.04.12node18

How cool is all that? I admit that while I find Node.js pretty interesting, I don’t have a whole lot of enterprise-type scenarios in mind yet. But, playing with Node.js gave me a great excuse to try out the handy Cloud9 IDE while flexing Iron Foundry’s newfound love for polyglot environments.

What do you think? Have you tried web-only IDEs? Do you have any sure-thing usage scenarios for Node.js in enterprise environments?



Categories: Cloud, Cloud Foundry

4 replies

  1. To include Mustache, today (Nov/2012) the line is:
    var Mustache = require(‘mustache/mustache.js’);

Trackbacks

  1. New Job, Different Place « Richard Seroter's Architecture Musings
  2. Deploy a Framework Friday #4 Some Node.js .gitignore Cloud 9 IDE Sharing toward Cloud Foundry / Iron Foundry Deployment « Composite Code
  3. Combining Clouds: Accessing Azure Storage from Node.js Application in Cloud Foundry « Richard Seroter's Architecture Musings

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: