Created
October 11, 2011 08:46
-
-
Save Raynos/1277598 to your computer and use it in GitHub Desktop.
Node vanilla REST server
This file contains hidden or 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
/* | |
A utility function to turn an object into a property descriptor hash | |
@param Object obj - the Object of keys & values to turn into an object of | |
keys and PropertyDescriptor(value) | |
*/ | |
var pd = function _pd (obj) { | |
var o = {}; | |
Object.keys(obj).forEach(function (key) { | |
var pd = Object.getOwnPropertyDescriptor(obj, key); | |
o[key] = pd; | |
}); | |
return o; | |
}; | |
module.exports = pd; |
This file contains hidden or 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
var http = require("http"), | |
pd = require("./pd.js") | |
Stack = require("./stack.js"); | |
var Resource = { | |
/* | |
Constructs a resource | |
@param Object props - A set of properties that will be mixed into the | |
resource | |
@return Resource | |
*/ | |
constructor: function _constructor(props) { | |
var r = Object.create(Resource, pd(props)); | |
r.stack = Stack.constructor(); | |
r.stack.use(function _handleResource(req, res, next) { | |
var cb = r.methods[req.method]; | |
if (cb) { | |
cb(req, res, next) | |
} else { | |
next(); | |
} | |
}); | |
return r; | |
} | |
}; | |
/* | |
Methods for the HTTP verbs | |
Examples: | |
resource.get(function(req, res) { res.end("GET!"); }); | |
@param Function cb - callback to be trigger when a http request | |
is made on the server for this verb | |
*/ | |
["get", "post", "put", "delete", "head", "options"].forEach(function (method) { | |
Resource[method] = function _method(cb) { | |
this.methods[method.toUpperCase()] = cb; | |
} | |
}); | |
var Rest = { | |
/* | |
creates an error handling piece of middleware | |
@return Function | |
*/ | |
error: function _error() { | |
return (function (req, res) { | |
res.statusCode = 500; | |
res.end("unexpected server error"); | |
}); | |
}, | |
/* | |
Generates a new Rest server | |
@return Rest | |
*/ | |
constructor: function _constructor() { | |
var r = Object.create(Rest, pd({ | |
stack: Stack.constructor(), | |
_resources: [] | |
})); | |
r._server = http.createServer(function _handleRequest(req, res) { | |
r.stack.handle({ | |
data: [req, res] | |
}); | |
}); | |
return r; | |
}, | |
/* | |
Listen to port | |
@param Number port - port to listen to | |
*/ | |
listen: function _listen(port) { | |
this._server.listen(port); | |
}, | |
/* | |
Adds a resource for an uri regular expression and | |
adds the methods to the resource | |
Examples: | |
rest.resource(/^\/blog$/, { | |
GET: function () { res.end("GET /blog"); } | |
}); | |
@param RegExp uri - A regular expression to match the url of | |
the incoming request to | |
@param Object methods - A hash of methods and callbacks | |
@return Resource | |
*/ | |
resource: function _resource(uri, methods) { | |
var resource = Resource.constructor({ methods: (methods || {}) }); | |
this._resources.push([uri, resource]); | |
return resource; | |
}, | |
/* | |
Generates a router for resources as middleware, intended | |
to be added to the server stack. | |
Examples: | |
rest.stack.use(server.router()); | |
@return Function | |
*/ | |
router: function _router() { | |
return (function _router(req, res, next) { | |
var pathname = req.url; | |
for (var i = 0, len = this._resources.length; i < len; i++) { | |
var tuple = this._resources[i], | |
regexp = tuple[0], | |
resource = tuple[1]; | |
if (regexp.test(pathname)) { | |
return resource.stack; | |
} | |
} | |
next(); | |
}).bind(this); | |
} | |
}; | |
module.exports = { | |
Rest: Rest, | |
Resource: Resource | |
}; |
This file contains hidden or 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
var rest = require("./lib/rest.js").Rest.constructor(); | |
// register router & error handler | |
rest.stack.use(rest.router()); | |
rest.stack.use(rest.error()); | |
// register GET / | |
rest.resource(/^\/$/, { | |
GET: function (req, res) { | |
res.end("hello world"); | |
} | |
}); | |
// register GET /trolls | |
rest.resource(/^\/trolls$/).get(function (req, res) { | |
res.end("trolls"); | |
}); | |
// start rest server | |
rest.listen(8080); | |
console.log("listen to port 8080"); |
This file contains hidden or 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
var toArray = function _toArray(arr) { | |
var ret = []; | |
for (var i = 0, len = arr.length; i < len; i++) { | |
ret[i] = arr[i]; | |
} | |
return ret; | |
} | |
var Stack = { | |
/* | |
constructor: Generates a new middleware stack | |
@arguments: Array - an array of middleware functions or stacks | |
@return Stack | |
*/ | |
constructor: function _constructor() { | |
var s = Object.create(Stack); | |
s._stack = []; | |
var middlewares = toArray(arguments); | |
middlewares.forEach(function (middleware) { | |
s.use(middleware); | |
}); | |
return s; | |
}, | |
/* | |
have the stack handle some data | |
Examples: | |
stack.handle({ | |
data: [req, res], | |
floor: next | |
}); | |
@param Object hash - a hash of information | |
{ | |
Array data - an array of data to pass to middlewares | |
Function ceil - a ceiling function for the stack, | |
this will be called first | |
Function floor - a floor function for the stack, | |
this will be called last | |
} | |
*/ | |
handle: function _handle(hash) { | |
var data = hash.data, | |
stack = toArray(this._stack); | |
hash.ceil && stack.unshift(hash.ceil); | |
hash.floor && stack.push(hash.floor); | |
(function _next() { | |
var handler = stack.shift(); | |
if (!handler) { | |
return; | |
} | |
if (handler.apply) { | |
handler = handler.apply(null, data.concat(_next)); | |
} | |
if (handler && handler.handle) { | |
handler.handle({ | |
data: data, | |
floor: _next | |
}); | |
} | |
})(); | |
}, | |
/* | |
Add a piece of middleware to the stack | |
@param Function|Stack middleware - a middleware stack or function to add | |
*/ | |
use: function _use(middleware) { | |
this._stack.push(middleware); | |
} | |
}; | |
module.exports = Stack; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment