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.
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.
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).
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 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 ;)
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>
<% } %>
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.
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.
Have you heard of nodejitsu/forever for keeping your server running?