DailyJS

Node Tutorial Part 21: Connection Management

Alex R. Young

Subscribe

@dailyjs

Facebook

Google+

tutorials server node lmawa nodepad

Node Tutorial Part 21: Connection Management

Posted by Alex R. Young on .
Featured

tutorials server node lmawa nodepad

Node Tutorial Part 21: Connection Management

Posted by Alex R. Young on .

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

Click to show previous tutorials.

Package Updates

I've updated all the packages to the latest versions. Express is now on
2.2.2!

HTML Preview

In the Backbone.js tutorials we already added a stub to
DocumentControls called showHTML. This is
meant to show the HTML preview, which can be obtained by viewing a
document with .html appended to the URL. I added a
convenience function to the model for getting the right URL:

  Document = Backbone.Model.extend({
    Collection: Documents,

    url: function() {
      return this.urlWithFormat('json');
    },

    urlWithFormat: function(format) {
      return this.get('id') ? '/documents/' + this.get('id') + '.' + format : '/documents.json';
    },

    // ...

Then added the event 'click #html-button': 'showHTML' to
DocumentControls and updated showHTML:

showHTML: function(e) {
  var model = this.model;
  e.preventDefault();
  $.get(this.model.urlWithFormat('html'), function(data) {
    console.log($(window).height());
    $('#html-container').html(data);
    $('#html-container').dialog({
      title: model.get('title'),
      autoOpen: true,
      modal: true,
      width: $(window).width() * 0.95,
      height: $(window).height() * 0.90
    });
  });
}

I'm using dialog from jQuery UI to display the contents of
the HTML document.

Express Responses

It was possible to make some of my server-side methods hang, like this
one:

app.post('/search.:format?', loadUser, function(req, res) {
  Document.find({ user_id: req.currentUser.id, keywords: req.body.s ? req.body.s : null },
                [], { sort: ['title', 'descending'] },
                function(err, documents) {
    switch (req.params.format) {
      case 'json':
        res.send(documents.map(function(d) {
          return { title: d.title, id: d._id };
        }));
      break;
    }
  });
});

This is poor style because an unrecognised format would cause the app to
hang. You should avoid this as much as possible when building Express
apps and always send something back to the browser:

app.post('/search.:format?', loadUser, function(req, res) {
  Document.find({ user_id: req.currentUser.id, keywords: req.body.s ? req.body.s : null },
                [], { sort: ['title', 'descending'] },
                function(err, documents) {
    switch (req.params.format) {
      case 'json':
        res.send(documents.map(function(d) {
          return { title: d.title, id: d._id };
        }));
      break;

      // Here
      default:
        res.send('Format not available', 400);
      break;
    }
  });
});

TJ Holowaychuk pointed this out to me in the comments.

I'm not sure if a 400 Bad Request is the best way to respond though.
What about 406 Not Acceptable? I'm sure there's a standard convention,
but I read through part of
rfc2616 and couldn't decide.

An additional way to safeguard against hung connections is by using
middleware to disconnect them after a period of time. The
Connect-timeout middleware by Guillermo Rauch could be used to do this. Long-running
connections are still allowed with this middleware by using the
clearTimeout method which gets added to the request
objects.

It's fairly easy to use:

var connectTimeout = require('connect-timeout@0.0.1'),
    // ...

app.configure(function() {
  app.use(connectTimeout({ time: 10000 }));
  // ...

There are options for error code and time.

This week's code is commit
2fde220
.