Eventually Consistent

Dispatches from the grey area between correct and working

Building an Express Blog Application

I'm in the process of rewiring the backend for Ethernet Bucket using Express. If you don't know what express is, here's a good primer. The goal today is to write something that can take blog entries in MongoDB (that part not covered) and turn them into web pages.

I’m in the process of rewiring the backend for Ethernet Bucket using Express. If you don’t know what express is, here’s a good primer. The goal today is to write something that can take blog entries in MongoDB (that part not covered) and turn them into web pages.

The first thing we need to do is install express.

npm install -g express

Then we initialize our project.

express MyBlog
# and then as per instructions
cd MyBlog
npm install

You’ll notice that express made a lot of files for you, most importantly are the files in the ‘routes’ folder and the files in the ‘views’ folder. The way I wanted my blog to work was for a url like “www.ethernetbucket.com/article/whatever” to link to the article “whatever”. Additionally I wanted the url “www.ethernetbucket/category/myCategory” to link to a page that listed articles of that category. To do this we need routes.

Article Route

Add a file to the routes folder called article.js. To get it setup to query Mongo add something like this:

var databaseUrl = "myDatabase",
    collections = ["articles"],
    db = require("mongojs").connect(databaseUrl, collections),
    u = require("underscore");
   // also probably a good time to install underscore and mongojs
exports.servePage = function (req, res){
}

We’re setting up a function called ‘servePage’ that express will use to to respond to requests for articles. In order to hook this function into the process of an article request, we have to modify app.js in the top of the directory. App.js comes looking like this:

var express = require('express');
var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var app = express();
// all environments
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(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}
app.get('/', routes.index);
app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

We’re going to replace ‘user’ with article. So line something like this:

var user = require('./routes/user');
  // changes to
var article = require('./routes/article');
  // and 
app.get('/users', user.list);
  // changes to
app.get('/article/:article_name', user.servePage);

Now express will route (hence the name) all get requests that are of the format “/article” to our servePage function that does something which we haven’t written yet. Lets fill it in…

exports.servePage = function (req, res){
   db.articles.findOne({url: req.params.article_name},function(err,result){
      if (err) {
         // oops - we'll deal with this later
      } else if (!result){
         // oops again - this would be a 404
      } else {
         res.render('article', result);
      }
   })
}

Two things happening here. First in the mongo query I reference “req.params.article_name”. This parameter was defined in app.js at the same time we defined the route for article. The second thing is at the end there you see “res.render(‘article’,result)”. This tells express to render the view ‘article’ (yet to be written) with the data from mongoDB.

Article View

In the views folder, you see index.jade and layout.jade; both are jade templates (duh). layout.jade has “blocks” that can be filled by other templates which “extend” layout.jade. We need an article.jade file. It should look like this:

extends layout
block css
	each val in css
		link(rel='stylesheet', href='/stylesheets/'+val.file)
block headertags
	!= headertags
block content
	article
		if hidetitle == false
			h2= title
		if publishDate
			date
				strong= publishDate
		each val in content
			if val.type == 'p'
				p= val.text
			if val.type == 'h2'
				h2= val.text
			if val.type == 'HTML'
				!= val.text
			if val.type == 'pre'
				div.codebox
					header Code
					pre.prettyprint.linenums.lang-js= val.text

The template above actually makes the page you’re looking at right now. The ‘blocks’ hook into certain parts of layout.js that looks like this:

doctype 5
html
head
title= title
script(src='/javascripts/example.js')
link(rel="stylesheet",href='/stylesheets/example.css')
block css
block headertags
    body
        header(id='masthead')
            h1
                a(href='/') My Blog!!!
        nav
            //- perhaps some nav stuff here
        block content
        footer
            p Copywrite 2013
            script
        window.onload = function(){
            // do some code
        }

You can see there there is example javascript and css files included in layout.jade. These files would live in the ‘public’ directory created by express when we initialized our project. Using a layout template is really awesome because we can put any other template, for example the template for the category page, into the layout. So if we need to change our nav section or change our stylesheets we only have to go to one place and make one change.

Finishing up

What we have so far is enough to get articles to render using the /article route. Some things that will need to be done in the future are making a 404 and 503 template to let readers know of errors. We need to fill out our index.jade template because its pretty bare at this point. And obviously we havent written the route for category or the view for it, but I think you can see from what we’ve done so far how you should go about doing it.

If you want to see what this project ultimately came to be checkout Wato Blog Tool

Thanks for reading! If you found this helpful, consider sharing it.