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.
From here, I can create a new project by clicking the “+” icon above My Projects.
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.
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.
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.
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.
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.
Clicking that link took me to my application hosted by Cloud9.
With no URL parameters (just “/”), the web function was called. If I add “/service” to the URL, I see a JSON result.
Cool! Just to be thorough, I also threw the “/web” on the URL, and sure enough, my web function was called.
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.
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.
What comes up is a wizard where I chose to deploy to Cloud Foundry (but could have also chosen Windows Azure, Joyent or Heroku).
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.
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.
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.
In seven seconds, the deployment was done and I was provided my Iron Foundry URL.
Sure enough, hitting that URL (http://seroternodetest.ironfoundry.me/service) in the browser resulted in my Node.js application returning the expected response.
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?
To include Mustache, today (Nov/2012) the line is:
var Mustache = require(‘mustache/mustache.js’);