Node.js: A Jumpstart for Devs

Posted on Sep 17, 2013 (31 weeks ago). Seen 11,788 times. 14 comments. Permalink Feed
Photo Jeremy Osborne
Instructor
NewCircle, Inc.
Member since Apr 29, 2013
Location: San Francisco Bay Area
Stream Posts: 1

Intro

Node.js1. The cool kids are using it. My mom is using it. My grandma is using it. Even my urbanized chickens are using it. But what are they using it for, and how are they using it? My name is Jeremy Osborne, and if you’re like me, you’re a nerd. You probably also find yourself wanting to use Node.js but you may not know where to begin.

I’m not here to tell you that you should use Node.js. In fact, I’m often the person telling people not to use Node.js for things it’s not good for. For example: please don’t write a bunch of commandline shell scripts in Node.js. There are other languages and systems that do that better.

I do assume you are watching these videos because you are smart, you are already technical, you have heard of Node.js, and you’d like to just know where to get started. I’d like to provide some suggestions – in the form of code and some demonstrations – that will give you an idea of what you can do with Node if you just know where to begin.

This is not designed to be a one size fits all solution. This is a one-size-gets-you-started solution. By the end of this short tutorial, what I hope is that I save you time, even if it’s only a few minutes or a few hours, on your Node learnings and adventures.

Enough talk, let’s code!

01. Installing Node.js

To be as general as possible, we’ll install node from the Node.js downloads2 page. The version of node I’m running is:

node --version
v0.10.13

The Node Package Manager (npm3) should come along for free nowadays. The version of npm that I’m using is:

npm --version
1.3.6

02. Building our Project

No one builds a production app in 10 minutes. That’s silly to even assume that with today’s tools. But this is a test, and we want to see what we can do in a short amount of time. And to do much at all, we’ll need some help from the previous brave developers who’ve jumped into the Node.js world and have created tools for all of us to use.

Since we want to use the express web framework4, let’s install it to our project folder:

mkdir app-sprint
cd app-sprint
npm install express@3.3.4

Excellent! Notice that we now have a node_modules folder in our directory. By default, npm does not install things globally, which is good when you need to have different projects with different dependencies. The express framework comes with a command that we can use to initialize our application. Since we did not install express globally, let’s run the command using the local script:

node_modules/express/bin/express

Most excellent! We now have some project scaffolding. One of the most important pieces is the package.json5 file. The package.json file is really no just for publishing a finished package to the npm repository. It is a great management tool for dealing with the package dependencies of our project. There are very good resources on the web about how to make the most of a package.json file. Learn it, love it.

We want to see if there are any additional dependencies up front that our application needs:

npm install

When run locally, this installs all of our project and developer dependencies. Righteous!

Did we screw something up yet? Let’s make sure by running the hello world version of our application:

npm start
# which is the same as...
# node app.js

And visit our test application at:

http://localhost:3000/

Express says hello world to us :) Not bad. We have a running test server, a sample page, and we’re pretty sure at this point that node and npm work after just a few minutes work.

03. Handlebars: Switching the Template Engine

What people call Template Engines nowadays are all solutions to getting the HTML out of JavaScript/Python/PHP/Ruby/Insert Other Language here. If you haven’t really used a template engine, explore the subject.

What if we want to use a different template engine than the one that comes with express (which is Jade)? It’s pretty easy to write our own bootstrap into express, but let’s take the easy way out and use one predone for us. I like Handlebars6, and to include in our project:

npm install express3-handlebars@0.5.0 --save

We download the dependency, and along the way --save our dependency to our package.json file. Righteous, take a look!

cat package.json

No more editing JSON (okay, at least no more editing it all the time).

As the tagline says, express3-handlebars7 is:

A Handlebars view engine for Express which doesn't suck.

To save time, I’m stealing the basic views that are provided and I’m going to dump the JADE views that are included:

rm views/*.jade
cp -R node_modules/express3-handlebars/examples/basic/views/* views/

Mainly because our application is going to be tiny.

Express needs to know about the view engine, and our main script is app.js. Let’s open it up and:

// Add this include
var exphbs  = require('express3-handlebars');

// ... some other code ...

// Comment out Jade.
//app.set('view engine', 'jade');
// Add in express3-handlebars.
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');

// ... some other code ...

// Get rid of routes.
//app.get('/', routes.index);
//app.get('/users', user.list);
// For example, just code in our stuff..
app.get('/', function (req, res) {
    res.render('home');
});

And try things out:

node app.js

Awesome, Handlebars works!

04. Adding our First Template (the magic check-in button)

This application that really isn’t an application will be really simple. We’re going to click a button, find out where we’re located at (as best as the browser can determine), and save all of the places that we’ve checked into.

Let’s make our big button. Open views/home.handlebars and change the code to be:

<h3>Where have I been?</h3>
<form action="/" method="POST">
    <input type="hidden" name="latitude" value=""/>
    <input type="hidden" name="longitude" value=""/>
    <button type="submit" class="btn btn-primary btn-lg" disabled>Check In!</button>
</form>

But that’s to plain. Let’s make it better with Twitter Bootstrap8. This is a bit old fashioned, but effective.

# grab the file
wget http://getbootstrap.com/2.3.2/assets/bootstrap.zip
unzip bootstrap.zip
# Move everything
cp -R bootstrap/css/* public/stylesheets/
# Get rid of what we don't need.
rm -rf bootstrap bootstrap.zip

Let’s plug it into our templates. Open views/layouts/main.handlebars and add to the head tag:

<link rel='stylesheet' href='/stylesheets/bootstrap.min.css'/>
<link rel='stylesheet' href='/stylesheets/bootstrap-responsive.min.css'/>
<link rel='stylesheet' href='/stylesheets/style.css'/>

Refresh the application (or start it again with node app.js and reload) and make sure things look a bit different. Awesome!

Side note: The default express settings treat the public/ folder as the document root and will attempt to serve static files from there. That’s why we only need to alter our handlebars template to make things work.

05. Geolocation: a Usable HTML5 API

One of the easiest APIs to take advantage of in the browser is the Geolocation API9. It’s what we will use to track ourselves. We will plug this into a client side JavaScript file at public/javascripts/client.js:

(function() {
    var noGeolocation = function() {
        alert("For some reason we are unable to find your location. Sorry.");
    };

    if (!navigator.geolocation || !document.querySelector) {
        noGeolocation();
    }
    else {
        navigator.geolocation.getCurrentPosition(
            function(p) {
                document.querySelector("[name='latitude']").value = p.coords.latitude;
                document.querySelector("[name='longitude']").value = p.coords.longitude;
                document.querySelector("[type='submit']").removeAttribute("disabled");
            },
            function(err) {
                noGeolocation();
            }
        );
    }
})();

And then include the script at the bottom of views/home.handlebars:

<script src="javascripts/client.js"></script>

Test it out! Right now, the only visible change is that the submit button will go from disabled to enabled. If we open the debugger, we can see that the form coordinate fields, the hidden ones, now have guesstimated latitude and longitude.

06. Geolocation: Making it Human Friendly

Latitudes and longitudes are for machines. I want to know where the computer thinks I’m at, so I’m going to use the Yahoo Query Language10 and their geo.placefinder endpoint. The geo.placefinder acts as a reverse geocoder, which means we can turn a latitude/longitude into an address (best guess, of course). Let’s make a routes/index_post.js file, and add the following to it:

var request = require("request");

// Proxy through YQL.
var whereURL = 'http://query.yahooapis.com/v1/public/yql?format=json&q=select * from geo.placefinder where gflags="R" and text="{LAT},{LON}"';

// express extends the Node concept of request/response HTTP architecture,
// but also keeps true to the basic idea.
var revgeo = function(lat, lon, callback) {
    var url = whereURL.replace("{LAT}", lat).replace("{LON}", lon);

    request(url, function(error, response, contentBody) {
        // Attempt to build the interpoloated address, or fail.
        var address;
        try {
            address = JSON.parse(contentBody).query.results.Result;
            address = Array.isArray(address) ? address[0] : address;
            address = address.line1 + " " + address.line2;
        }
        catch(e) {
            callback("Could not retrieve the location at "+lat+", "+lon);
            return;
        }

        if (error || response.statusCode != 200) {
            callback("Error contacting the reverse geocoding service.");
        }
        else {
            callback(null, address);
        }
    });
};

module.exports = function(req, res) {
    var latitude = req.body.latitude;
    var longitude = req.body.longitude;

    revgeo(latitude, longitude, function(err, address) {
        // diagnostic
        console.log(latitude, longitude, err, address);

        res.render('home', {
            error: err,
            location: {
                latitude: latitude,
                longitude: longitude,
                address: address
            }
        });
    });
};

Let’s make use of this in our app.js:

// After the app.get('/', ....) code...

// Handle form posts:
app.post('/', require('./routes/index_post.js'));

Restart and attempt to run…. Aw snap! We’re using a library we haven’t downloaded yet called request11. No matter, let’s fix it:

npm install request@2.27.0 --save

Let’s try again… DY-NO-MITE! We have an address output to our console.log. Who knows how good it is, shall we ask the NSA?

07. Dynamic HTML: Making Use of Our Templates

Templates are great. When we want to update them, we can. We have an error and an address that we want to show on the page. Once again, let’s modify views/home.handlebars and add the following:

{{! below the form, above the script tag }}


{{#if error}}
<p class="text-warning">{{error}}</p>
{{/if}}
{{#if location}}
<p>
    The browser says you are at <strong>{{location.latitude}}, {{location.longitude}}</strong>.
</p>
<p>
    This lat/lon seems to equate to:
    <blockquote>{{location.address}}</blockquote>
</p>
{{/if}}

Try it out. You can now track yourself. Groovy!

08. Simple Persistence with SQLite and an ORM Package

How much more fun would it be if we could track ourselves and one up the NSA? Yeah baby! To do that, let’s use an ORM package for Node called node-orm212. We’ll need a few things, so let’s grab the package:

# The node ORM package.
npm install orm@2.1.0 --save

We’re going to use a simple sqlite313 database, so we also need to include that package:

# The sqlite3 driver.
npm install sqlite3@2.1.7 --save

Since most things in Node tend to be non-blocking, we need to start managing the flow of our app with more callbacks. Let’s make a very, very simple database module that handles just what we need. Create src/db.js and drop the following in it:

var orm = require("orm");

// Will be set on init, null == not set.
module.exports.Breadcrumb = null;

// Callback will be called when done.
module.exports.init = function(done) {
    orm.connect("sqlite://breadcrumbs.db3", function (err, db) {
    var Breadcrumb = db.define("breadcrumb", {
        date: Date,
        latitude: Number,
        longitude: Number,
        address: String,
    });
    // Make the database.
    Breadcrumb.sync(function(err) {});
        if (err) {
            done("Error: could not create the database: " + err);
        }
        else {
            // Export our object for basic interactions.
            module.exports.Breadcrumb = Breadcrumb;
            // We're done.
            done(null);
        }
    });
};

And in app.js let’s make sure we create our database before anything else happens:

// ...with the rest of the includes at the top of the file...

// Our simple database.
var db = require("./src/db");

// ... at the bottom of the file ...

// Initialize the database before starting the server.
db.init(function(err) {
    if (err) {
        console.log(err);
    }
    else {
        http.createServer(app).listen(app.get('port'), function(){
          console.log('Express server listening on port ' + app.get('port'));
        });
    }
});

Run our application. Nothing should be different on the web side, but we should now have a database file within the base folder.

09. Tracking ourselves

Let’s feed each of our checkins into a database. Crack open routes/index_post.js and modify:


// ...at the top of the file...

// Access to the database.
var db = require("../src/db");

// ...in the revgeo function before the success callback...

var revgeo = function(lat, lon, callback) {
    // ...code...

    request(url, function(error, response, contentBody) {
        // ...more code...
        else {
            // Save an address.
            db.Breadcrumb.create([
                {
                    date: new Date(),
                    latitude: lat,
                    longitude: lon,
                    address: address
                }
            ], function (err, items) {
                // err - description of the error or null
                // items - array of inserted items
                // Pass back both err and address at this point.
                callback(err, address);
            });
        }
    });
};

Check out the database. Getting populated with the most exciting places we’ve ever been!

10. Displaying Places We’ve Been

Now that we’re storing our checkins, let’s display our trail of breadcrumbs whenever we checkin. Open up routes/index_post.js one more time and:

// ...in the call to revgeo...

revgeo(latitude, longitude, function(err, address) {
    // diagnostic
    console.log(latitude, longitude, err, address);

    db.Breadcrumb.find(function(err, items) {
        res.render('home', {
            error: err,
            location: {
                latitude: latitude,
                longitude: longitude,
                address: address
            },
            // Make the breadcrumbs available on checkin.
            breadcrumbs: items
        });
    });
});

And let’s make the breadcrumbs available in our views/home.handlebars:

{{! ...below everything else we've added but above the script tag... }}

{{#if breadcrumbs}}
<h4>You appear to have also checked in at:</h4>
<ul>
    {{#each breadcrumbs}}
    <li>({{date}}): we visited {{address}}</li>
    {{/each}}
</ul>
{{/if}}

Track yourself. You are now PRISM. Be proud.

And there we have it, a rudimentary application in a short amount of time that can get you in trouble, and give you lots of fun.

Managing our Project with Grunt (Bonus!)

Projects can get large very quickly, and this project, for a web project, is something I’d consider on the cusp of getting out of control. Even without a compilation step, there’s unit testing, static analysis, packaging, and many other parts of the software development process to worry about. Although we won’t worry about it here, what does Node have in terms of task management? My favorite is Grunt14, an excellent task management tool. To use Grunt, we need to install a global commandline task runner, which we can do with:

npm install -g grunt-cli@0.1.9

Let’s als0 get the Grunt project scaffolding15 builder… thing-a-ma-jig:

# The grunt init tool.
npm install -g grunt-init@0.2.1
# A grunt config template.
git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile

Before we outro, let’s setup a simple task that checks our code via grunt using JSHint16.

# Build our basic Gruntfile
grunt-init gruntfile

# ... answer the questions ...

# Install our tools as devDependencies
npm install grunt@0.4.1 --save-dev
npm install grunt-contrib-jshint@0.6.3 --save-dev
npm install grunt-contrib-watch@0.5.3 --save-dev

And let’s setup our code to go through static analysis every time we save anything. Open up the newly formed Gruntfile.js and change it to the following:

/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Task configuration.
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        browser: true,
        globals: {}
      },
      all: {
        src: ['Gruntfile.js', 'app.js', 'src/**/*.js', 'routes/**/*.js',],
      },
    },
    watch: {
      scripts: {
        files: ['Gruntfile.js', 'app.js', 'src/**/*.js', 'routes/**/*.js'],
        tasks: ['jshint'],
      },
    },
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  span class="co">// Default task.
  grunt.registerTask('default', ['jshint']);

};

And let’s try out our Makefile… I mean our Gruntfile:

grunt

Holy cow! We have some changes to make to make JSHint happy! Static analysis is great, it’s like compiler warnings when we use a compiled language, and we can now make these code changes.

Conclusion

As we’ve seen, taking advantage of what Node.js is good at, and then augmenting it with packages from npm can make for a very rich development environment for web-centric applications. Node.js has matured over it’s brief lifetime, and while I feel it appropriate to say that Node still has more maturing to do, I think we’ve seen that we’re finally at the point where the question isn’t should I use Node.js, but what should I use it for?

I do hope this tutorial saved you some time, and I wish you great luck in your coding adventures.

References

Project Files: nodejs-app-spring.zip


  1. Node.js?

  2. Node.js download?

  3. Node Package Manager (npm) and package repo?

  4. express web framework for node?

  5. A package.json cheat sheet?

  6. Handlebars: Template Engine?

  7. A Handlebars view engine for Express which doesn’t suck.?

  8. Twitter Bootstrap?

  9. Browser based geolocation API?

  10. Yahoo Query Language?

  11. Simplified HTTP requests for Node?

  12. An ORM package for Node?

  13. sqlite3 bindings for Node?

  14. Grunt: JavaScript Task Runner?

  15. Grunt project scaffolding?

  16. JSHint static analysis for JavaScript?

Comments

Posted on Sep 19, 2013
Photo Cal Enti
Indepednent
Member since Sep 19, 2013
I registered with this site just so I could leave a comment. Excellent tutorial.

I think it might be good for the articles longevity to take the versions out of it - for instance, when I went to install node it was at 11.18, and the sqlite3@2.1.7 driver failed. I was able to complete this tutorial by removing version numbers (so sqlite3 instead of sqlite3@2.1.7 did the trick).

Awesome tutorial, though. Easy to follow and produced something usable in the end.
Posted on Sep 20, 2013
Photo Jeremy Osborne
Instructor
NewCircle, Inc.
Member since Apr 29, 2013
Location: San Francisco Bay Area
@Cal Enti excellent work digging into the dev branch of node (which is the .11 branch at this time). I tend to act like a crotchety man and stick to stable branch stuff for things like this, and it's nice to know you and others could yank off the version numbers should you wish to.

Thank you for taking the time to try things out, and for taking a moment to leave feedback here. Good luck to you in your work.
Posted on Nov 21, 2013
Photo Ben CS
Communications
Member since Nov 21, 2013
Fine tutorial. New to Node and Express. A bit confused about Express installation.
Do you need to create a new project folder and install Express every time a new project is started?
ie.
mkdir <project name>
cd <project name>
npm install express@3.3.4

every time you create a new project? Cant you install Express just once?
Posted on Nov 22, 2013
Photo Jeremy Osborne
Instructor
NewCircle, Inc.
Member since Apr 29, 2013
Location: San Francisco Bay Area
Hi Ben,

You can install express globally if you really want to with:

npm install -g express

npm has taken the approach of doing local vs. global installs by default, which is a different compared to other package/dist systems. It's a bit of a pain if you really do intend to use one and only one version of express on a system that has different apps, hence the ability to do global installs like above.

However, the local install is (at least to me) a great boon when those moments arrive and I need to have multiple installs of the same application on a system. No virtualenv needed, just a normal:

npm install express
Posted on Nov 27, 2013
Photo Ben CS
Communications
Member since Nov 21, 2013
Hello Mr. Osborne,
Thank you for the reply.
In a production env running Node.js , i suppose you need to install Express only once(?)
In that case where will you install Express in a production env? Do you need to install it in a separate folder? or Should you install it in the Nodejs installation folder?
After installation, does Express need to be configured ? like setting up env variables.....etc?
Thanks.
Posted on Nov 28, 2013
Photo Jeremy Osborne
Instructor
NewCircle, Inc.
Member since Apr 29, 2013
Location: San Francisco Bay Area
Hi Ben,

The option is really yours. express isn't a huge install. If you are really having many apps use the exact same version of express, sure, do a global install. I just did an `npm i express` (which brought down version 3.4.5) and checked the disk usage: 4.5 megabytes, which isn't much.

It sounds like you're pretty new to express, and I'd recommend sitting down and getting used to it, as I won't be able to solve all of your questions here. Like many things Node, it's new. Sometimes documentation is awesome, sometimes it is not. The best thing to do right now is get your hands dirty with code, and express is one where using it for awhile will teach what you need to know (hopefully).

For express, I'd recommend looking through their example code:

https://github.com/visionmedia/express/tree/master/examples

If you're really new, I'd also recommend looking over connect, which is a module that express is based on:

http://www.senchalabs.org/connect/
Posted on Nov 28, 2013
Photo Jeremy Osborne
Instructor
NewCircle, Inc.
Member since Apr 29, 2013
Location: San Francisco Bay Area
Also, I forgot to add that I recommend reading about how node require finds those modules that you're looking for. I'd recommend reading this entire page:

http://nodejs.org/api/modules.html

And committing the following sections to memory:

http://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders

http://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
Posted on Nov 30, 2013
Photo Ben CS
Communications
Member since Nov 21, 2013
Hello Mr. Osborne

Thanks once again for those tips and links.
I got a lot to catch up...
Posted on Jan 29, 2014
Photo Maddula Harish
chat
theinitium group
Member since Jan 29, 2014
Hi this is harish. We done the above tutorial it is working good and really nice stuff in it. We are working with phonegap for multiple platforms.now we have a requirement i.e chat between two persons.is it work for mobiles for android and iPhone.Thanks in advance.
Posted on Jan 29, 2014
Photo Maddula Harish
chat
theinitium group
Member since Jan 29, 2014
Hi this is harish. we are working with phonegap for multiple platforms.now we have a requirement i.e chat between two persons.is it work for mobiles for android and iPhone.Thanks in advance
Posted on Jan 29, 2014
Photo Maddula Harish
chat
theinitium group
Member since Jan 29, 2014
HI Jeremy Osborne. is it work for mobile platform like iOS and android. Kindly revert me back as soon as possible. Thanks in advance
Posted on Jan 30, 2014
Photo Jeremy Osborne
Instructor
NewCircle, Inc.
Member since Apr 29, 2013
Location: San Francisco Bay Area
Hi Harish,

A bit of a short answer, but given you ask a pretty broad question: maybe check out Web Sockets + Node.js? Start with Socket.io as a starting point to give you some ideas.
Posted on Jan 31, 2014
Photo Maddula Harish
chat
theinitium group
Member since Jan 29, 2014
Hi Jeremy Osborne, we worked with web sockets and Node.js.we worked the whole thing in web applicatipn. it is working fine and it is working in our local netwotk but the problem is sync with our database port is not listening can u suggest me some idea. is it finished means then we are going to implement in mobile as (iOS and in android).Kindly revert me back as soon as possible. Thanks in advance
Posted on Jan 31, 2014
Photo Maddula Harish
chat
theinitium group
Member since Jan 29, 2014
Hi Jeremy Osborne, we worked with web sockets and Node.js.we worked the whole thing in web applicatipn. it is working fine and it is working in our local netwotk but the problem is sync with our database port is not listening can u suggest me some idea. is it finished means then we are going to implement in mobile as (iOS and in android).Kindly revert me back as soon as possible. Thanks in advance