Getting started with VMware CloudFoundry, MongoDB and Node.js
Listen to the recording of the Node.js Panel Discussion webinar.
Overview
Following up from our previous post we’re posting up a quick how-to for using Node.JS, CloudFoundry and MongoDB together.
Our end goal here is to build a simple web app that records visits and provides a reporting screen for the last 10 visits.
Tools We Need
- Sign up for a Cloud Foundry account.
- Local installation of MongoDB & Node.JS.
- Cloud Foundry VMC tools.
- All of the code is available on github.
Getting Started
- Start the
mongod
process on your local computer. Use the default port. - Confirm that node.js is correctly installed. You should be able to run
node
from the command-line and receive a basic javascript shell. You should also have NPM (node package manager) installed. - Make a directory for the project and then ensure that CloudFoundry is correctly configured. Mine looked as follows:
Step 1: Hello world
In your directory create a file called app.js
. In that file, type the following code. This will create a basic web server on localhost:3000 or on the assigned host:port combination on the CloudFoundry server.
var port = (process.env.VMC_APP_PORT || 3000); var host = (process.env.VCAP_APP_HOST || 'localhost'); var http = require('http');http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(port, host);
Test our file locally:
$ node app.js $ curl localhost:3000 Hello World # kill node with CTRL+C
Push our file to CloudFoundry and test. CloudFoundry automatically picks up that we’re using node.js,but it will ask some other configuration questions, including a name and the services we want to have running. I have named mine gvp_node_test
and requested that MongoDB be run as a service.
The commands & output:
$ vmc push Would you like to deploy from the current directory? [Yn]: Y Application Name: gvp_node_test Application Deployed URL: 'gvp_node_test.cloudfoundry.com'? Detected a Node.js Application, is this correct? [Yn]: Y Memory Reservation [Default:64M] (64M, 128M, 256M, 512M, 1G or 2G) Creating Application: OK Would you like to bind any services to 'gvp_node_test'? [yN]: y The following system services are available:: 1. mongodb 2. mysql 3. redis Please select one you wish to provision: 1 Specify the name of the service [mongodb-55516]: Creating Service: OK Binding Service: OK Uploading Application: Checking for available resources: OK Packing application: OK Uploading (0K): OK Push Status: OK Staging Application: OK Starting Application: OK
At this point you should have a simple working web app. Note the URL: your_app_name.cloudfoundry.com
, we can test it is working with curl
.
$ curl your_app_name.cloudfoundry.com Hello World
Step 2: getting mongo configs
CloudFoundry has now configured a MongoDB service with its own user name, password, ip and port. To access these on the server, we will need to parse the environment variables coming into the node
process.
To do this we do the following, note that we’ve added an else
clause so that we can run this locally.
if(process.env.VCAP_SERVICES){ var env = JSON.parse(process.env.VCAP_SERVICES); var mongo = env['mongodb-1.8'][0]['credentials']; } else{ var mongo = {"hostname":"localhost","port":27017,"username":"", "password":"","name":"","db":"db"} }
The code wraps this up in a generate_mongo_url
function that provides a “connection string” of the form mongodb://username:password@host:port/db_name
.
Copy in the rest of the code from step 2 on github and test locally.
$ node app.js $ curl localhost:3000 # connection string for localhost
Once that’s working push the update to the cloud. Notice that we add the name of the project and we don’t get asked any questions:
$ vmc update your_app_name Uploading Application: ... Stopping Application: OK Staging Application: OK Starting Application: OK # test again $ curl your_app_name.cloudfoundry.com # bunch of environment variables
Step 3: now with drivers
First we need to install the node-mongodb-native
driver. To do this, we use NPM.
$ npm install mongodb
You should see a new directory at the end of this process: node_modules
. To enable use to include these module on the cloud we add this path to the require
variable at the top of the code.
require.paths.unshift('./node_modules');if(process.env.VCAP_SERVICES){ ...
Our goal here is to build a function for recording a visit. Let’s build that function.
var record_visit = function(req, res){ /* Connect to the DB and auth */ require('mongodb').connect(mongourl, function(err, conn){ conn.collection('ips', function(err, coll){ /* Simple object to insert: ip address and date */ object_to_insert = { 'ip': req.connection.remoteAddress, 'ts': new Date() };/* Insert the object then print in response */
 /* Note the _id has been created */
 coll.insert( object_to_insert, {safe:true}, function(err){
 res.writeHead(200, {'Content-Type': 'text/plain'});
 res.write(JSON.stringify(object_to_insert));
 res.end('\n');
 });
});

}); }
Notice the .connect
and .collection('ips'...)
. We’re telling it to store data in the ips
collection.
Another nice feature is the object_to_insert
. Saving a document with Node+MongoDB is as simple as creating the object and inserting it.
Let’s fix up the main createServer
function.
http.createServer(function (req, res) { record_visit(req, res); }).listen(port, host);
Then we can test locally and push with vmc
. If this is working locally, you should be able to connect to your local mongod instance and see some data in the ips
collection.
$ mongo localhost:27017/db > db.ips.find() ...
Step 4
At this point, you’ve probably tested a few times and you’ve successfully put data in the database. Now it’s time to get that data out.
Let’s create a function to print the last 10 visits:
var print_visits = function(req, res){ /* Connect to the DB and auth */ require('mongodb').connect(mongourl, function(err, conn){ conn.collection('ips', function(err, coll){ /*find with limit:10 & sort */ coll.find({}, {limit:10, sort:[['_id','desc']]}, function(err, cursor){ cursor.toArray(function(err, items){ res.writeHead(200, {'Content-Type': 'text/plain'}); for(i=0; i < items.length; i++){ res.write(JSON.stringify(items[i]) + "\n"); } res.end(); }); }); }); }); }
Let’s update the createServer
method to print when we request /history
.
http.createServer(function (req, res) { params = require('url').parse(req.url); if(params.pathname === '/history') { print_visits(req, res); } else{ record_visit(req, res); } }).listen(port, host);
Again, we test locally and then upload with vmc
. If it all works, you should be able to do this:
$ vmc update your_app_name ... $ curl your_app_name.cloudfoundry.com {"ip":"172.30.49.42","ts":"2011-06-15T20:14:18.977Z","_id":"4df9129af354f8682d000001"} $ curl your_app_name.cloudfoundry.com {"ip":"172.30.49.43","ts":"2011-06-15T20:14:21.745Z","_id":"4df9129df354f8682d000002"}now let's test history
$ curl gvp_node_test.cloudfoundry.com/history {"ip":"172.30.49.43","ts":"2011-06-15T20:14:21.745Z","_id":"4df9129df354f8682d000002"} {"ip":"172.30.49.42","ts":"2011-06-15T20:14:18.977Z","_id":"4df9129af354f8682d000001"} ...
Going further
- Check out our upcoming Node.js Panel Discussion webinar.
- For some MongoDB wrappers take a look at
- For building more complex web sites take a look at the Express framework.
– Gates Voyer-Perrault
@gatesvp