Frontend med Node och Express, backend med WordPress och JSON API

I somras så fick jag tillsammans med en kollega i uppdrag att förnya en existerande webbplats. Några av sakerna vi hade i åtanke var att den skulle vara responsiv, intuitiv och byggas med något annat än bara WordPress.

Vi började rota runt i Node.js och Express och tänkte att det var något vi ville använda. En av styrkorna med WordPress är ju däremot att det är väldigt enkelt att administrera innehåll i det, så vi valde att använda tillägget JSON API tillsammans med WordPress. På så sätt kunde innehållet hämtas via JSON och på så sätt kan frontenden bara vara ett skal som slussar information.

Backend

Som backend så rullade som sagt WordPRess och JSON API. Vi upptäckte ganska tidigt att tillägget var utdaterat när det gäller stödet för custom post types och taxonomies. Vi byggde enkelt ut vår plattform med de funktioner vi behövde. Anta att denna sida rullar på http://backend.dev och det aktiva temat i sig genererar ingen utdata.

Frontend

Basen på frontenden byggdes med hjälp av Node.js och Express. Ett av kraven i funktionaliteten var att vi inte ville att sidan skulle laddas om. Därför använde vi:

  • Sammy.js för att hantera URL:er
  • Futures för att hantera callback-röran (enligt mig) som kan uppstå och för att se till att saker och ting sker asynkront
  • Node-dirty för att skapa en lokal cache av JSON anropen som görs mot http://backend.dev
  • Restler för att göra REST-anrop mot http://backend.dev
  • Forever för att se till att servern hålls igång.
  • Cluster för att styra applikationen

Exempel på en modell som representerar en klient:

var Model   = require('./model'),
    API     = require('./api'),
    config  = require(__dirname + '/../conf/' + (global.process.env.NODE_ENV || 'development') + '.js');

function Client(args) {
  Model.prototype.constructor.call(this, args);  
}

Client.prototype = new Model();

Model.extend(Client, API);

Client.singleUrl = function(slug){ return config.wordpress.url + '/api/CustomTheme/get_taxonomy_posts/?taxonomy=client&slug=' + slug + '&custom_fields=service,type'; };
Client.collectionUrl = function(){ return config.wordpress.url + '/api/CustomTheme/get_taxonomy_keys/?taxonomy=client'; };

Client.singleKey = 'posts';
Client.collectionKey = 'posts';
Client.model = Client;

Client.prototype.constructor = Client;
Client.prototype.render = function() {
  return {
    id:         this.data.term_id, 
    title:      this.data.name,
    slug:       this.data.slug
  };
};

module.exports = Client;

API är en generell klass som alla modeller använder sig av, och Client.singleUrl och Client.collectionUrl är den URL som API:t ska använda sig av, göra anropet, cacha resultatet och generera en struktur som controllern sedan använder sig av.

Cachen är satt på väldigt hög timeout. Det är en webbplats som inte besökaren har någon möjlighet att påverka innehållet på. Så därför behövde vi komma på en lösning att varje gång en uppdatering skett i WordPress-backenden så rensades vår cache.

Hela miljön deployas med hjälp av Capistrano. Där användes en Rakefile för att hantera situationer som att starta om servern, stoppa servern och rensa cachen.

Summan av kardemumman

En ganska krånglig lösning men oerhört kul och inspirerande att få genomföra. Tyvärr blev det tidsbrist och jag hade inte tid att slutföra projektet innan jag åkte till San Jose. Projektet gav mig absolut mersmak för Node.js och vi får se vad jag hittar på i framtiden.

Förra terminen här i San Jose så läste jag en kurs där ett delmoment var i Node, så där hade jag absolut försprång på de andra i klassen. Jag ber om ursäkt för att jag inte kan visa mer kod än vad jag har gjort.