DailyJS

Node Tutorial Part 7

Introduction

Alex R. Young

Subscribe

@dailyjs

Facebook

Google+

tutorials server node lmawa nodepad npm express

Node Tutorial Part 7

Posted by Alex R. Young on .
Featured

tutorials server node lmawa nodepad npm express

Node Tutorial Part 7

Posted by Alex R. Young on .

Welcome to part 7 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.

Previous tutorials:

Package Versions

I've updated the Nodepad
README

to include the versions of Node and Mongo that I'm using. It also
includes the versions of the packages I've used. That should help you
actually get the code running if it doesn't seem to work. I've tested it
on Mac OS and Debian.

Also remember that you need to restart Node whenever you change code
(but not Jade templates).

We're using npm to install packages, and it sets up path
names so specific package versions can be required. To install a package
at a specific version, do this:

npm install express@1.0.0

Then to use it, do this:

var express = require('express@1.0.0');

You can verify this works by typing node and entering the
previous line:

> express = require('express@1.0.0')
{ version: '1.0.0'
, Server: { [Function: Server] parseQueryString: [Function] }
, createServer: [Function]
}

Jade Tricks

When I first demonstrated Jade I hardcoded all the attributes. It's
possible to save a lot of effort by writing selectors as a shorthand for
classes and IDs:

div#left.outline-view
  div#DocumentTitles
    ul#document-list
      - for (var d in documents)
        li
          a(id='document-title-' + documents[d].id, href='/documents/' + documents[d].id)
            =documents[d].title

Notice that an ID selector has been combined with a class name:
div#left.outline-view.

The default tag is div, which means the previous example
can be reduced to this:

#left.outline-view
  #DocumentTitles
    ul#document-list
      - for (var d in documents)
        li
          a(id='document-title-' + documents[d].id, href='/documents/' + documents[d].id)
            =documents[d].title

Error Pages

Express allows us to define a custom error handler with
app.error:

// Error handling
function NotFound(msg) {
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
}

sys.inherits(NotFound, Error);

// This method will result in 500.jade being rendered
app.get('/bad', function(req, res) {
  unknownMethod();
});

app.error(function(err, req, res, next) {
  if (err instanceof NotFound) {
    res.render('404.jade', { status: 404 });
  } else {
    next(err);
  }
});

app.error(function(err, req, res) {
  res.render('500.jade', {
    status: 500,
    locals: {
      error: err
    } 
  });
});

Error handlers get four parameters, the error, req, res, and next. The
next method can be used to pass the error on to the next
handler. In the previous example, the 404 handler passes on errors that
aren't NotFound, and we effectively catch all other errors
and consider them 500s.

Visiting /bad in the browser will display the custom 500
page. Notice that I specify the HTTP status code in the options for
render -- it's important to correctly specify status codes
else a 200 will be returned instead of a 404 or 500.

Error Handling within Mongoose Code

The next method is available to all of our app HTTP verb
methods, which means we can use it to render a custom 404 page:

app.get('/documents/:id.:format?/edit', loadUser, function(req, res, next) {
  Document.findById(req.params.id, function(d) {
    if (!d) return next(new NotFound('Document not found'));
    // Else render the template...

This is the pattern that I found easiest to read when using Mongoose.
Simply using throw new NotFound within a Mongoose callback
will cause the application to crash rather than Express's error handlers
being triggered.

Conclusion

When distributing or deploying Node applications it's important to be
specific about package versions. Many key packages are still under heavy
development, so distribution in particular can be difficult.

Express makes it fairly easy to create custom error handlers with
templates, but make sure you specify the HTTP status code and use
next(exception) when in a callback.

This version of Nodepad was in commit
929f564
.