Node Tutorial Part 2

08 Nov 2010 | By Alex Young | Tags server node tutorials lmawa nodepad

Welcome to part 2 of Let’s Make a Web App, a tutorial series about building a web app with Node. This series will walk you through the major areas you’ll need to face when building your own applications. These tutorials are tagged with lmawa.

Part 1 introduced this series and discussed how to select appropriate libraries for your Node projects.

This part covers installing the basic tools and libraries, and we’ll also create a skeleton app and take a look at the generated code.

Requirements

This project depends on the following:

  • A working Node install
  • MongoDB
  • npm

I’ll walk you through the installation of each of these. Refer to part 1 to see why I decided to use these technologies.

Installation: Node

If you don’t have Node installed download it and decompress it. I’m using 0.2.4. You could also use a package manager if you have one on your system. There are Debian packages, Homebrew recipes, and more besides.

You should be able to build and install Node like this:

./configure
make
make install

You may need to change the permissions of the installation directory before running make install, or use sudo or su.

These steps will work for a unix-based system. If you’re using Windows you’ll have to figure this part out for yourself, but running Node on Windows is possible.

MongoDB

I want to use MongoDB for our database. It’s also pretty easy to install — there are packages and compilation should be straightforward. The site has lots of binaries available.

MongoDB needs a data directory, which can be created with mkdir -p /data/db. This is the default path, but it can be changed. I use the default on all my development machines.

The MongoDB Quickstart Guide is a good place to start for more installation help.

npm

npm makes managing Node packages quicker and easier than fetching their source. The recommended installation method is to run a command that downloads a script and installs npm somewhere you have permission to write.

If you’re developing on your own machine, you could chown -R $USER /usr/local and run curl http://npmjs.org/install.sh | sh.

Alternatively, build Node with its prefix somewhere in your home directory:

./configure --prefix=~/local

npm will then see this and install its packages alongside Node. There are detailed instructions in gist 579814.

Packages

Now we’ve got npm our required packages can be installed:

npm install express mongoose jade less expresso

Don’t be put off by npm’s verbosity, the messages are actually fairly easy to follow. Just make sure it prints Success for each package.

A Basic Express App with MongoDB

When I work with Mongo, I usually start a local server. This is straightforward:

mongod

It’ll display the port it’s using, which you needs to be noted down for the Mongoose connection settings.

Express ships with a commandline utility for creating apps. Change to a suitable directory and type this to generate a skeleton app:

express nodepad

The resulting code should run with node app.js. View it by visiting http://localhost:3000.

Skeleton Analysis

The first line is standard CommonJS: the express module is required, and the app is created and exported — that just makes it easier to test, don’t worry if this doesn’t make sense yet.

Express has changed a lot in the last year, so be careful with old tutorials because they may use a different API. Since the initial release, connect has been added, which is a middleware layer. This allows certain chunks of the HTTP stack and web app framework to be interchangeable. Configuration in particular has changed a lot.

What you should be seeing is this:

app.configure(function() {
  app.set('views', __dirname + '/views');
  app.use(express.bodyDecoder());
  app.use(express.methodOverride());
  app.use(express.compiler({ src: __dirname + '/public', enable: ['less'] }));
  app.use(app.router);
  app.use(express.staticProvider(__dirname + '/public'));
});

By default Express apps are very simple — notice the view path is specified, and a static file handler is set up with staticProvider. express.bodyDecoder is just used to decode application/x-www-form-urlencoded data — i.e., forms. The methodOverride middleware allows Express apps to behave like RESTful apps, as popularised by Rails; HTTP methods like PUT can be used through hidden inputs. There has been a lot of dispute about whether this is a good idea, which is presumably why Holowaychuk has made it optional.

The main body of the app uses a jade template to generate HTML, and sets a variable to pass to the template:

app.get('/', function(req, res) {
  res.render('index.jade', {
    locals: {
        title: 'Express'
    }
  });
});

This method call defines a route and corresponding HTTP verb, GET and ‘/’. That means this little chunk of code won’t respond to a POST to ‘/’.

The last few lines are interesting because they actually check if the app is running as the top-level module:

if (!module.parent) {
  app.listen(3000);
  console.log("Express server listening on port %d", app.address().port)
}

Again, this makes testing easier; don’t worry if it seems strange.

Connecting Up MongoDB

Mongoose allows us to conveniently wrap simple classes around Mongo collections. We need to load the library and instantiate a database connection instance first:

mongoose = require('mongoose').Mongoose
db = mongoose.connect('mongodb://localhost/nodepad')

I’ve made a models file with an example model:

var mongoose = require('mongoose').Mongoose;

mongoose.model('Document', {
  properties: ['title', 'data', 'tags'],

  indexes: [
    'title'
  ]
});

exports.Document = function(db) {
  return db.model('Document');
};

The models can be required in app.js, like this:

Document = require('./models.js').Document(db);

The database instance is passed, so db.model will return a model instance based on the mongoose.model('Document', ...) declaration. I thought putting the models in their own file would make the Mongoose behaviour a little more opaque so the application controller code is easier to follow.

The Templates

The generator uses Jade by default, and it created this template:

h1= title
p Welcome to #{title}

This is similar to Haml, and it attempts to reduce the noise of HTML templates. If you like plain HTML templates an alternative like ejs can be used.

Running Tests

The Express generator also created a skeleton test. The tests are run by typing expresso.

Get the Source

This is available on my GitHub account at alexyoung/nodepad.

Conclusion

You should now be comfortable with installing a base Node development environment with npm and mongo. You should also have a skeleton Express app, and understand how it works and how to run Expresso tests.

I’ll flesh out the app a little bit more next week.


blog comments powered by Disqus