Simple Node.js Express MVR Template

In this post we’ll walk through how to setup a simple MVR Node.js project using Express, Mongoose (MongoDB), Jade (templating) and everyauth (authentication). First off, what the fuck is MVR, think MVC but with routes instead controllers.

What we’re going to be using

Setup

You’re going to need Node.JS, NPM, and MongoDB installed. If you haven’t done that yet see Building and Installing Node.js and MongoDB Quickstart.

Open up the command line to create the project

$ npm install -g express-generator
$ express examplemvr
$ cd examplemvr
$ rm -rf ./routes
$ rm public/stylesheets/style.css
$ mkdir models
$ npm install

Now open the mongo console and insert some test data

$ mongo nodemvr
$ db.examples.insert({name:'Test Doc'});

Dependencies

Open the examplemvr project in your favorite text editor and edit package.json to match the following

package.json

{
    "name": "application-name"
  , "version": "0.0.1"
  , "private": true
  , "dependencies": {
      "express": "2.5.8"
    , "jade": ">= 0.0.1"
    , "mongodb": ">= 0.9.6-7"
    , "mongoose": ">= 2.5.10"
    , "everyauth": ">=0.2.32"
  },
  "engines": {
    "node": ">= 0.6.14",
    "npm":  "1.0.x"
  }
}

This tells NPM what modules we need and the versions we require. Now open up the command line again to update your modules with NPM

$ npm install

This will tell NPM to read the package.json and install any dependencies that are needed.

Application Core

Now open app.js and edit it to match the following

/app.js

var express = require('express');
var app = module.exports = express.createServer();
app.everyauth = require('everyauth');
app.everyauth.helpExpress(app);
app.mongoose = require('mongoose');

var config = require('./config.js')(app, express);

var models = {};
models.examples = require('./models/example')(app.mongoose).model;

require('./routes')(app, models);

app.listen(process.env.PORT || 3000);

Review

Let’s review this a few lines at a time.

Require express and assign the server to the “app” object.

var express = require('express');
var app = module.exports = express.createServer();

Require everyauth and load the helpers

app.everyauth = require('everyauth');
app.everyauth.helpExpress(app);

Require mongoose

app.mongoose = require('mongoose');

Require the config file and pass it some variables to use, we’ll go through this later

var config = require('./config.js')(app, express);

Create the object to hold our models and then require them (is this example we only have 1 model)

var models = {};
models.examples = require('./models/example')(app.mongoose).model;

Require the routes

require('./routes')(app, models);

Set the server to listen on a port (process.env.PORT is for production deployment, ie heroku)

app.listen(process.env.PORT || 3000);

Setup the config

Create a new file under the root of the project named “config.js” and edit it to match the following

/config.js

module.exports = function(app, express, mongoose){

  var config = this;

  app.requireAuth = true;

  //configure everyauth
  app.everyauth.twitter
     .consumerKey('yourKey')
     .consumerSecret('yourSecret')
     .findOrCreateUser( function (session, accessToken, accessTokenSecret, user) {
       return 1;
  }).redirectPath('/');

  //generic config
  app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({ secret: 'topsecret' }));
    app.use(app.everyauth.middleware());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
  });

  //env specific config
  app.configure('development', function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));

    app.mongoose.connect('mongodb://localhost/nodemvr');
  });

  app.configure('production', function(){
    app.use(express.errorHandler());

    app.mongoose.connect('mongodb://flame.mongohq.com:27087/nodemvr');
  });

  return config;

};

I’ll let you spend some time to figure out what each little bit of this does but the gist of it is that it sets up your twitter information for authentication and then various config settings which should be pretty self explanitory.

NOTE - you will need to setup an application on dev.twitter.com to obtain a key and secret if you want to use authentication. If not, just set app.requireAuth = false.

Models

Now let’s create out example model. We’re going to be using Mongoose for MongoDB.

/models/example.js

module.exports = function(mongoose) {
  var collection = 'examples';
  var Schema = mongoose.Schema;
  var ObjectId = Schema.ObjectId;

  var schema = new Schema({
    author: ObjectId,
    name: String,
    date: Date
  });

  this.model = mongoose.model(collection, schema);

  return this;
};

Set your collection and build out you’re schema.

Views

Edit the index.jade and layout.jade to match the following

/views/layout.jade

!!!
html
    head
        title= title
        link(rel='stylesheet', href='/stylesheets/bootstrap.min.css')

    body
        div.topbar.navbar.navbar-fixed-top
            div.fill
                div.container
                    a(href='/').brand #{title}


    div.container!= body
        footer
            p
                | Node.js MVC template by
                a(href='http://benedmunds.com')(target='_blank') Ben Edmunds


/views/index.jade

div.hero-unit
    h1 Heading

div.content
    div.row
        div.span12
            h2 Sub-Heading
            ul.unstyled.indent
                each example in examples
                    li
                        a(href="example/#{example._id}")  #{example.name}

We’ll be using twitter’s bootstrap for our styling so go grab the img, and js from Github and we’ll use a customized version of the spacelab theme for bootstrap which you can get from Gist. Place them under their respective folder in the public directory. Your new directory structure should look like the following

public/
    - images/
        glyphicons-halflings-white.png
        glyphicons-halflings.png
    - javascripts/
    	bootstrap.min.js
    - stylesheets/
    	bootstrap.min.css

Routes

Now for the final step we’re going to create the routes to glue this all together, in the root of your project create a file named “routes.js” and insert the following

/routes.js

module.exports = function(app, models){

  app.get('/', function(req, res){

    if (app.requireAuth === true && req.loggedIn === false)
      res.redirect('/auth/twitter');

    //get all the rides
    models.examples.find({}, function(err, docs){

      //render the index page
      res.render('index.jade', {
          locals: {
            title: 'Example',
            search_placeholder: 'Search',
            examples: docs
          }
      });

    });
  });

};

Review

We’ll walk through this one in more detail.

Create a route to respond to /

module.exports = function(app, models){

  app.get('/', function(req, res){

If requireAuth is true in our config then require authentication

 if (app.requireAuth === true && req.loggedIn === false)
      res.redirect('/auth/twitter');

Get the example data from the model

models.examples.find({}, function(err, docs){

Render the index.jade template with our data

res.render('index.jade', {
  locals: {
    title: 'Example',
    search_placeholder: 'Search',
    examples: docs
  }
});

Done!

Open the command line and start your app

$ node app.js

Get the code

You can get the code for this project on Github. I’m fairly new to node and this is a work in progress so if you see anywhere this can be improved feel free to send a pull request.

Translations

This page has been translated into Spanish language by Maria Ramos from Webhostinghub.com/support/edu.

Have fun!


April 19 2012