Skip to content

Instantly share code, notes, and snippets.

@pacovell
Forked from indexzero/some-resource.js
Created August 26, 2011 20:28
Show Gist options
  • Save pacovell/1174359 to your computer and use it in GitHub Desktop.
Save pacovell/1174359 to your computer and use it in GitHub Desktop.
An example of a possible "resource" API in node.js
var util = require('util'),
resourceLib = require('our-new-resource-lib');
var SomeResource = function (options) {
resourceLib.Resource.call(this, options);
//
// Setup any other application specific state.
//
// Define actions (these default actions would likely be in the parent resource; shown here as an example)
var actions = [
{ name: 'index', method: 'get', scope: 'collection' },
{ name: 'show', method: 'get', scope: 'element' },
{ name: 'edit', method: 'get', scope: 'element' },
{ name: 'update', method: 'put', scope: 'element' },
{ name: 'new', method: 'get', scope: 'collection' },
{ name: 'create', method: 'post', scope: 'collection' },
{ name: 'destroy', method: 'delete', scope: 'element' },
];
this.addActions(actions);
//
// Require authentication on all actions, authorize on edit, update, delete
// Can also be added later, as below
//
this.before('all', 'authenticate');
this.before(['edit', 'update', 'delete'], 'authorize');
//
// Around filter structured like this
/*
function log(original, req, res, next) {
// before
original(req, res, function() {
// after
next();
});
};
*/
this.around('all', 'log');
//
// Setup this resource to use CouchDB.
//
// PAC: not sure what you're going to do based on this? Will this store or set up a database object?
// this.set('db', couch);
};
util.inherits(SomeResource, resourceLib.Resource);
//
// Actions support a series of "filters", executed in the order added
// Can also be added in initialization
//
SomeResource.before(['edit', 'update', 'delete'], 'authorize'); // call by name on this
SomeResource.before(['edit', 'update', 'delete'], authorize); // or use a function
SomeResource.before('index', function(req, res, next) {
// Also can be declared 'inline' so you can organize functional groups
db.spaceMonkeys.findOne({_id: req.query.spaceMonkeyId}, this.setCallback('spaceMonkey'));
// If we are very clever, next will execute after all the this.setCallback() are completed,
// and we won't need a separate async library here.
next();
});
SomeResource.prototype.index = function(req, res, next) {
// TODO: need a way to cleanly render different results for different request types -- eg,
// a status message for JSON/JS, or a page render for a web client.
this.set('monkeyLevel', 5);
// Render will have any 'set' values passed in as locals that can be used in view rendering
this.render(next);
};
SomeResource.after('index', function(req, res, next) {
this.spaceMonkey.save(next);
});
@pacovell
Copy link
Author

For testing, need to have a nice way to load a controller resource, exercise an action with mocked resources, and check any local set variables, return codes, etc

@indexzero
Copy link

I like where this is going. From an implementation standpoint it seems like the dependency tree would look like

our-new-resource-lib
`-- resourcer / mongoose [database communication] 
`-- journey / express    [routing implementation]

@pacovell
Copy link
Author

Yes, except I'm interested in having the routing implementation just emit an event for the right resource and then consider it handled. Is this feasible?

@pacovell
Copy link
Author

And, I'm going to replace mongoose with a very thin layer on mongodb native

@indexzero
Copy link

I think events is the right way to integrate with the routing layer. In this way you can easily decouple them. Also, if you're dropping mongoose we should talk about how we could pull that into a resourcer engine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment