Created
August 26, 2011 01:41
-
-
Save aviflax/1172499 to your computer and use it in GitHub Desktop.
resource.js for Express
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var Resource = require('../lib/resource'); | |
var ResourceError = require('../lib/resourceerror'); | |
var Goal = require('../models/Goal'); | |
var GoalResource = new Resource(); | |
GoalResource.get = function(req, res) { | |
var self = this; | |
Goal.get(req.params.id, function(err, goal) { | |
if (err) | |
return self.err(500, err, res); | |
res.send(JSON.stringify(goal), {'Content-Type': 'application/json'}); | |
}); | |
} | |
GoalResource.put = function(req, res) { | |
var self = this; | |
Goal.get(req.params.id, function(err, goal) { | |
if (err) | |
return self.err(500, err, res); | |
goal.update(req.body, function(err) { | |
if (err) | |
return self.err(409, err, res); | |
res.send(JSON.stringify(goal), {'Content-Type': 'application/json'}); | |
}); | |
}); | |
} | |
module.exports = GoalResource; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var async = require('async'); | |
var Resource = require('../lib/resource'); | |
var Goal = require('../models/Goal'); | |
var AllGoalsResource = new Resource(); | |
AllGoalsResource.representations = {} | |
AllGoalsResource.representations.json = function(req, res) { | |
getGoals(function(err, goals) { | |
if (err) | |
return AllGoalsResource.err(500, err, res); | |
res.send(JSON.stringify(goals), {'Content-Type': 'application/json'}); | |
}); | |
} | |
AllGoalsResource.representations.html = function(req, res) { | |
getGoals(function(err, goals) { | |
if (err) | |
return AllGoalsResource.err(500, err, res); | |
renderHTML(goals, req.linkPrefix, function(html) { | |
res.send(html, {'Content-Type': 'text/html'}); | |
}); | |
}); | |
} | |
function getGoals(cb) { | |
async.parallel([ | |
function(cb) { | |
Goal.list('main', 'goals_by_group', {key:'now'}, function(err, goals) { | |
if (err) | |
cb(err); | |
else | |
cb(null, {'now': goals.toArray()}); | |
}); | |
}, | |
function(cb) { | |
Goal.list('main', 'goals_by_group', {key:'next'}, function(err, goals) { | |
if (err) | |
cb(err); | |
else | |
cb(null, {'next': goals.toArray()}); | |
}); | |
}, | |
function(cb) { | |
Goal.list('main', 'goals_by_group', {key:'later'}, function(err, goals) { | |
if (err) | |
cb(err); | |
else | |
cb(null, {'later': goals.toArray()}); | |
}); | |
}, | |
], function(err, results) { | |
var result = {}; | |
results.forEach(function(object) { | |
for (var propname in object) { result[propname] = object[propname]; } | |
}); | |
cb(err, results); | |
}); | |
} | |
function renderHTML(goals, linkPrefix, cb) { | |
var fs = require('fs'), | |
jsdom = require('jsdom'), | |
weld = require('weld'); | |
jsdom.env('html/goals.html', function (err, window) { | |
weld.weld(window.document.getElementById('goals-now'), goals.now); | |
cb(doc.innerHTML); | |
}); | |
} | |
module.exports = AllGoalsResource; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var ResourceError = require('./resourceerror'); | |
function Resource() { | |
if ( !(this instanceof arguments.callee) ) { | |
throw new Error("Constructor called as a function."); | |
} | |
} | |
Resource.prototype.attach = function(app, path) { | |
// TODO: consider supporting an array of paths | |
// for some bizarre reason, Express doesn't support HEAD | |
// see: https://github.com/visionmedia/express/issues/37 | |
var allMethods = ['del','get','options','patch','post','put']; | |
var supportedMethods = []; | |
var self = this; | |
allMethods.forEach(function(method) { | |
if (method in self && typeof(self[method]) == 'function') { | |
var handler = self[method]; | |
handler = handler.bind(self); | |
handler = wrapErrorHandler(handler); | |
app[method](path, handler); | |
supportedMethods.push(method == 'del' ? 'DELETE' : method); | |
} else if (method != 'options') { | |
app[method](path, methodNotAllowed); | |
} | |
}); | |
if (!('options' in self)) { | |
app.options(path, function(req, res) { | |
var methodList = supportedMethods.toString().toUpperCase(); | |
res.send(204, {'Allow': methodList}); | |
}); | |
} | |
} | |
function methodNotAllowed(req, res) { | |
res.send('405 Method Not Allowed', { 'Content-Type': 'text/plain' }, 405); | |
} | |
function wrapErrorHandler(handler) { | |
/* This is really of limited value, because errors will only be caught by the try/catch | |
if the resource throws them during its own execution, and not in an async callback. | |
*/ | |
return function(req, res) { | |
try { | |
handler(req, res); | |
} catch (e) { | |
var code = e instanceof ResourceError ? e.code : 500; | |
res.send(e.message, {'Content-Type': 'text/plain'}, code); | |
} | |
} | |
} | |
Resource.prototype.representations = null; | |
Resource.prototype.get = function(req, res) { | |
var reps = this.representations; | |
if (!reps || (typeof(reps) === 'object' && Object.keys(reps).length === 0)) | |
return methodNotAllowed(req, res); | |
for (var type in reps) { | |
if (req.accepts(type)) | |
return reps[type].call(this, req, res); | |
} | |
res.send('406 Not Acceptable', { 'Content-Type': 'text/plain' }, 406); | |
} | |
Resource.prototype.err = function(code, error, res) { | |
// this is an annoying and inelegant helper function for dealing with errors | |
res.send(error, { 'Content-Type': 'text/plain' }, code); | |
} | |
module.exports = Resource; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment