In a previous post, I wrote about enhancing Vardyger's API by adding support for content negotiation (e.g., application/json or text/html). In this post, we'll enhance the API by adding support for the Handlebars templating engine and Ghost themes.
Handlebars
Handlebars is a popular extension of the Mustache templating language that is easy to integrate and provides a familiar syntax.
We'll start by installing the express-hbs
package:
npm install express-hbs --save
Then we need to configure the API (in server.js
) to use Handlebars as its default view engine:
var express = require('express'),
hbs = require('express-hbs');
var app = express();
...
// Vardyger/content/themes/{theme name}
var themeDir = path.resolve(__dirname +
'../../../content/themes/' + 'casper');
// Use `.hbs` as the default template extension
app.engine('hbs', hbs.express4({
layoutsDir: themeDir,
defaultLayout: themeDir + '/default.hbs',
partialsDir: themeDir + '/partials'
}));
app.set('view engine', 'hbs');
app.set('views', themeDir);
...
Note: Because we want to support Ghost themes we need to follow their file structure:
├── /assets
└── /css
├── screen.css
└── /fonts
└── /images
└── /js
├── /partials [optional]
├── default.hbs
├── index.hbs
├── page.hbs [optional]
├── post.hbs
├── package.json
Note: layouts
(e.g., default.hbs) and views
(e.g., post.hbs) are in the theme's root directory.
The Vardyger file structure:
├── /content
└── /themes
└── /casper
└── /...
├── /core
└── /client
└── /server
└── /api
└── /...
└── /shared
Ghost Themes
We've configured the API to use Handlebars but to render a post (GET /posts/{id}
) using a Ghost theme we also need to configure the @blog property (in server.js
) that provides access to global data properties in Ghost themes:
var themeData = {
title: 'Rob Ferguson',
description: 'My personal blog about technology ...',
url: 'http://localhost:10010',
navigation: true
};
hbs.updateTemplateOptions({ data: {blog: themeData} });
I also needed to create 'stubs' for most of Ghost's helpers:
And, to correctly format the (post) response object:
function formatResponse(model) {
return {
meta_title: model.metaTitle,
meta_description: model.metaDescription,
navigation: [{
label: 'Home',
url: url,
current: false,
slug: ''
}, {
label: 'About',
url: url + '/about',
current: false,
slug: 'about'
}],
post: {
id: model._id,
title: model.title,
excerpt: model.html,
html: model.html,
url: 'http://localhost:10010',
image: model.image,
featured: model.featured,
page: model.page,
published_at: model.publishedAt,
updated_at: model.updatedAt,
created_at: model.createdAt,
author: {
name: 'Rob Ferguson',
location: 'Sydney, Australia'
},
tags: ''
}
}
}
Now, run MongoDB:
ulimit -n 1024 && mongod --config /usr/local/etc/mongod.conf
Start the API server:
swagger project start
And try it out, from the command line:
curl http://localhost:10010/v1/posts/{id} --header "Accept: text/html"
Or, from your browser:
References:
- Express.js: Fast, unopinionated, minimalist web framework for Node.js
- Handlebars.js: Minimal Templating on Steroids
- Ghost Themes: Overview