Tim Roberts

Software Developer and Journeyman Writer

A Simple MVC Framework With Node and Express

I love frameworks. As soon as I dropped my programmer’s ego and learned to embrace well conceived conventions over configuration my development and deployment times felt the benefit. On the other hand, I like understanding what is going on underneath the hood which there is a danger of losing sight of when using a framework.

And this brings me to why I love node.js and express. For me they provide an boilerplate for a framework: the tools I need to quickly build my own conventions.

For sure, it’s pretty easy to build a site with express as it is, but shifting express closer to a MVC setup is simple.

MVC in layman’s terms.

When I used my first MVC framework I got bit bad. It’s not difficult to see why as a pattern it has stood the test of time. And here is all you need to know to start out:

  • M is for model. A place to define data structures and methods to interact with your data store.
  • V is for view. A place to manage everything the end user sees on his or her screen.
  • C is for controller. A place to take user requests, bring data from the model and pass it back to the view.

And that’s enough of that for now. Here’s how I arrange my express apps into a basic MVC structure.

First of all I need three folders in the root of my app.

  • models
  • views
  • controllers

Now on to the app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var express = require('express');
      ,http = require('http');
      ,path = require('path');
      ,app = express();
      ,fs = require('fs');

// database connection
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mydb');

// some environment variables
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// dynamically include routes (Controller)
fs.readdirSync('./controllers').forEach(function (file) {
  if(file.substr(-3) == '.js') {
      route = require('./controllers/' + file);
      route.controller(app);
  }
});

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

Much of this file is standard if you are generating your app with express, but there are some important lines. Line 5 is where we include the native fs module so we can dynamically read in our controllers. Then in lines 25 to 30 we read in all js files from the controllers directory. Line 13 is pretty important too as it tells express where we want to store our views.

Now whenever we add a js file to our controllers directory we can format it in such a way that it will contain a group of routes. Here is an example that I place in controllers/users.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var mongoose = require('mongoose')
var Video = require('../models/user');
module.exports.controller = function(app) {

/**
 * a home page route
 */
  app.get('/signup', function(req, res) {
      // any logic goes here
      res.render('users/signup')
  });

/**
 * About page route
 */
  app.get('/login', function(req, res) {
      // any logic goes here
      res.render('users/login')
  });

}

I choose to include my models on a per controller basis (lines 1 to 2), so in my MVC structure they are required in each controller. As modules are cached the first time they are loaded there is no overhead in doing this. Moreover I like having the reference to the models I am using in the file I am using them in.

Line 3 exports all of our routes in the controller function. From here on in you can use the express way of defining routes. But notice that I set my views like this: res.render('users/signup') which results in the view being loaded from views/users/signup.jade in this app.

Finally, for reference, here is what the model in models/user.js may look like:

1
2
3
4
5
6
7
8
9
Var mongoose = require('mongoose')
      ,Schema = mongoose.Schema
      userSchema = new Schema( {
          username: String,
          password: String
      }),
User = mongoose.model('user', userSchema);

module.exports = User;

I like doing things this way because the controller is mediating both the models and the views which for me is the spirit of MVC. There is also a huge organisational win too: if I want to work on users/signup I know I that my model is in models/user.js; my route is in controllers/users.js and my view is in views/users/signup.jade. And that is what makes MVC such a great pattern.

MongoDB for Developers Certificate

Today I received my MongoDB for Developers certificate. Here it is in most of its glory:

MongoDB for Developers Certificate

I’d recommend anyone interested in learning about MongoDB to give it a go. The course is 6 weeks long and you also get to learn a bit of Python along the journey. As it’s offered by 10gen, the company who develop MongoDB, it’s probably the best source of learning on the subject.

There are a few courses specialised by language which you can find on their list of mongodb courses.

I’m now on my first week of MongoDB for Node.js developers, and I hear there may be a C# one in the pipeline.

Sending Emails With Node.js and Amazon SES

In a nutshell: SES is a reliable way to unload the burden of sending emails. Here’s how to harness Amazon’s Node.js SDK to send emails. The example below is a raw Node.js app, but should be easy enough to integrate with your framework of choice – e.g. Express / Geddy.

I’ve posted all the code in an example on github.

Some prerequisites

  1. An Amazon AWS account with SES enabled.
  2. Your Amazon Key and Secret.
  3. Verfiy an email address at SES.

First, install the Amazon SDK.

npm install aws-sdk

Or you can add it as a dependency to your package.json:

{
    "dependencies": {
        "aws-sdk": "latest"
    }
}

Then create a config file to hold your amazon credentions – e.g. config.json:

{ "accessKeyId": "YOURAMAZONKEY", "secretAccessKey": "YOURAMAZONSECRET", "region": "us-west-2" }

This example is a single script, but it would work just fine integrated into an express route etc. There’s an explanation below:

// load aws sdk
var aws = require('aws-sdk');

// load aws config
aws.config.loadFromPath('config.json');

// load AWS SES
var ses = new aws.SES({apiVersion: '2010-12-01'});

// send to list
var to = ['email@example.com']

// this must relate to a verified SES account
var from = 'emailc@example.com'


// this sends the email
// @todo - add HTML version
ses.sendEmail( { 
   Source: from, 
   Destination: { ToAddresses: to },
   Message: {
       Subject:Source {
          Data: 'A Message To You Rudy'
       },
       Body: {
           Text: {
               Data: 'Stop your messing around',
           }
        }
   }
}
, function(err, data) {
    if(err) throw err
        console.log('Email sent:');
        console.log(data)console;
 });

The ses.sendEmail passes a json string with the necessary parameters required by Amazon SES. This example sends a text message, but if you look over the docs for the sendEmail call you will a HTML version can be easily passed (along with a host of other parameters).

The callback function accepts the defacto err argument for collecting any errors and above use the second parameter data to output the information the service sends back on a successful send.

Where to go from here.

The next logical step in this script would be to read in a text file for the body so you can send templated emails. Look to Node.js’ fs to achieve something like that.

You could also wrap this functionality in a module so you can reuse it across your app with a more succint syntax..

Async Unique Validation With Expressjs and Mongoose

In a nutshell: here is how to add elegant validation with a useful error message for a field being unique. This is great for usernames, email addresses etc. that can only appear once in your collection.

Line 16 onwards are the ones to note. It’s a custom validation rule set on “email”. What’s important is that it adds a callback to the validate function which I have arbitrarily named respond. Notice that I can now search for an existing user and in the callback for that search, if a user is found, I can return false to my validation by passing false through my respond callback.

Resumable Polling With jQuery

Here’s a very simplified version of a technique I’ve used recently on our startup video platform, zumoflow. We needed a way of updating our mongodb engagement table periodically, only when a video was being played. For this we needed to set off a periodic poll when video play started and pause the poll when the video play was paused or stopped.

The following code shows the skeleton for two simple events. One to start and one to stop the poll:

// initialize a timer variable
// we need to use this to reference stopping the timeout

var timer;

// this function starts the poll and binds it to a variable called timer
// There's a configurable 2000 ms timeout on calling the function

function doPoll() {
    $.post('http://localhost', data, function(data) {
            timer = setTimeout(doPoll, 2000);
    })
}

Then we can attach the event to start the poll to any element:

$('.start').click( function() {
    doPoll();
    return false;
});

Finally we can attach the stop event which clears the timeout using the JavaScript clearTimeout function:

$('.stop').click( function() {
    clearTimeout(timer);
    return false;
});

References:

  1. jQuery $.post documentation
  2. window.setTimeout
  3. window.clearTimeout