Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Building my blog - a new website with node.js and geddy

Building my blog - a new website with node.js and geddy

return to withouttheloop.com

tl;dr I built an extremely simple blog engine with node.js and geddy. The code is at https://github.com/liammclennan/gistblog and my blog is at http://withouttheloop.com/

I have been wanting to move to a new blog for some time. My old blog runs on blogengine.net, which I don't particularly like. I want to get off blogengine and I want to get off windows. And I want to be able to write my posts in markdown.

Listening to Reginald Braithwaite on the leanpub podcast I discovered that he blogs on github. That gave me the idea of blogging using github gists to represent posts. Gists have a title, a created date, comments, markdown support and versioning - everything a good blog posts needs. My new blog engine is called gistblog.

Getting Gists Using the Github api

Github publish an api that, among other things, provides a feed of an author's gists. In my case, I can retrieve a list of my gists using the following http request:

GET http://gist.github.com/api/v1/json/gists/liammclennan

which returns a json list of gist metadata.

Identifying Posts

Not all of my gists are things that I want to publish as blog posts. By convention, my blog will display gists that have a filename beginning with blog_ and ends with .md (the markdown file extension).

Website Technology

I'm building my new blog with node.js, because that seems like fun and I like JavaScript. From previous experience I know that a good way to get started quickly building a node.js website is to use the geddy framework. Geddy is a simple rails-like framework. It has routing, mvc, a view engine and some infrastructure features to help with deployment.

The 'Posts' Controller

The Posts controller is responsible for rendering the front page of the blog - listing gists and linking to github. To make the call to the github api I use the request module. For anyone who has used jQuery this will look familiar.

request({ url: gistListUrl, json: true }, function (error, response, body) {
      console.log('get from github');
      if (!error && response.statusCode == 200) {
        cache = body;
        lastGet = new Date();
        successCallback(app, body);
      } else {
        errorCallback(app, body, response);
      }
});  

The second part of the controllers responsibility is to transform the github data into a format that suits my view. I use underscore.js:

app.respond({
        gists: _.chain(body.gists)
          .filter(isBlogGist)
          .map(toViewModel)
          .sortBy(date)
          .value().reverse()
});  

The _.chain() function copies the gist data into a underscore wrapper that lets me chain method calls in the fluent style. filter() reduces the set of data to those items that match the isBlogGist predicate (function returning a boolean). isBlogGist returns true if the filename begins with blog_ and ends with .md.

function isBlogGist(gist) {
      return /blog_.+\.md/.test(gist.files[0]);
}

.map() converts each data item by passing it through the toViewModel function, which returns data formatted for the view.

    function toViewModel(gist) {
      return { 
        id: gist.repo,
        description: gist.description, 
        filename: gist.files[0],
        created_at: new Date(gist.created_at),
        url: 'https://gist.github.com/' + gist.repo
      };
    }

Sort by and reverse are hopefully obvious ;)

The View

Geddy has a simple view template system called ejs. My view loops over the gists and renders a div for each one:

<% for (var i = 0; i < gists.length; i++) { var gist = gists[i]; %>

<div class="page-header well">
	<h1><a href=<%= gist.url %>><%= gist.description %></a></h1>
</div>

<% } %>

Deployment

I've always wanted my own linux server, so I signed up with linode. So far I am a big fan. The setup experience was great.

To convert my node.js process to a daemon (background process) I used upstart. My configuration file is:

#!upstart
description "gistblog"
author      "Liam McLennan"

start on startup
stop on shutdown

script
    export HOME="/home/liam"

    cd /home/liam/apps/gistblog
    echo $$ > /var/run/gistblog.pid
    exec /usr/local/bin/node /usr/local/lib/node_modules/geddy/bin/cli.js  >> /var/log/gistblog.sys.log 2>&1
end script

pre-start script
    # Date format same as (new Date()).toISOString() for consistency
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/gistblog.sys.log
end script

pre-stop script
    rm /var/run/gistblog.pid
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/gistblog.sys.log
end script

Next I tried to setup monit to monitor my process and restart it when it crashes. I couldn't get it to work so for now I just have to hope it doesn't crash.

The Source

If you would like to see the source, or even use it as your own blog engine, the project (gistblog) is hosted on github at https://github.com/liammclennan/gistblog.

@sirlancelot

This comment has been minimized.

Copy link

sirlancelot commented May 31, 2012

Have you heard of nodejitsu/forever for keeping your server running?

@liammclennan

This comment has been minimized.

Copy link
Owner Author

liammclennan commented May 31, 2012

forever looks great but I can't get it to work with geddy. I get this:

$ forever start /usr/local/lib/node_modules/geddy/bin/cli.js 
info:   Forever processing file: /usr/local/lib/node_modules/geddy/bin/cli.js

but the site does not start

@frio

This comment has been minimized.

Copy link

frio commented Jun 1, 2012

I forget the clause - it might be "restart" - but there is a command you can put in your upstart file to have it monitor and restart your process if it dies.

@liammclennan

This comment has been minimized.

Copy link
Owner Author

liammclennan commented Jun 1, 2012

thanks - I'll have a look for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.