Skip to content

Instantly share code, notes, and snippets.

@nicholatian
Created March 17, 2018 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicholatian/6289f383a53cd1a9b6f77b5ed29cf1d6 to your computer and use it in GitHub Desktop.
Save nicholatian/6289f383a53cd1a9b6f77b5ed29cf1d6 to your computer and use it in GitHub Desktop.
Super-generic Express routing in JavaScript
const router = Express.Router({
caseSensitive: true,
strict: true
})
exports.route = (uri, method, cb) => {
router[method.toLowerCase()](uri, cb)
}
/** ============================ F U N C T I O N ============================ *
* TITLE: Callback Generators
* DESCRIPTION: Functions that generate callback functions to be called by an
* Express router for a requested URI. While possibly confusing to
* some, this is a super-effective application of genericism in
* JavaScript.
* In our Express server, we map various routes using regular
* expressions, and couple them with code to serve an appropriate
* response. Writing this out long-hand is tedious, not nice for
* sysadmins, and bug-prone.
* Instead, we read in our collection of routes from a config
* file, and couple them with callbacks that Express recognises so
* we can send a response. On top of this, we make things not just
* DRY, but truly generic, by taking advantage of the fact that
* most routes often do the same or predictably similar tasks,
* which we categorise as actions such as `verbatim` or `redirect`
* or the like.
* When we run through the list of routes, we must create
* callbacks for each of them that have all of the right info to
* serve data. These route-specific callbacks are created by
* callback generators: there is one generator for each kind of
* route action to take. These generators hold all of the common
* context for their kind of routes, and all routes of that kind
* can share said data thanks to asynchronous control flow.
*/
const cbGen = {
verbatim: opts => {
const cwd = process.cwd()
const realRoot = opts.fileRoot === 'live' ? path.join(cwd, dist) :
opts.fileRoot === 'project' ? cwd :
process.platform === 'win32' ? 'C:' : '/'
const realPath = process.platform === 'win32' ?
opts.filePath.replace('/', '\\') : opts.filePath
return (req, res) => {
const serve = (err, data) => {
if(err) {
console.error(err)
return
}
res.send(data)
}
fs.readFile(path.join(realRoot, realPath),
opts.text === true ? 'utf-8' : null, serve)
}
},
redirect: opts => {
return (req, res) => {
res.redirect(307, opts.dest)
}
}
}
exports.loadConfig = () => {
const cfg = require('../config/routes')
for(let i = 0; i < cfg.length; i++) {
exports.route(cfg[i].uri, cfg[i].method, cbGen[cfg[i].action]())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment