'use strict' /** * represents the middleware stack for a url / method combination * @module skyring/lib/server/route * @author Eric Satterwhite * @since 1.0.0 * @requires path-to-regexp */ const pathToRegExp = require('path-to-regexp') /** * @constructor * @alias module:skyring/lib/server/route * @param {String} path the url pattern to match * @param {String} method The http method to respect * @example var rte = new Route('/foo/:id', 'POST') rte.use((req, res, node, next) => { if(req.method === 'DELETE') { const err = new Error('Not Implemented') err.statusCode = 501 next(err) } }) **/ function Route(path, method) { this.path = path this.method = method this._keys = [] this.stack = [] this.regexp = pathToRegExp(path, this._keys) this.keys = new Array(this._keys.length) this.params = Object.create(null) for( var idx = 0; idx < this._keys.length; idx++ ) { this.keys[ idx ] = this._keys[ idx ].name this.params[ this._keys[ idx ].name ] = undefined } } /** * Adds a middleware function to the end of the internal route stack * @method module:skyring/lib/server/route#use * @param {module:skyring/lib/server/route~Middleware} fn a the middelware function to add **/ Route.prototype.use = function use(fn) { if (Array.isArray(fn)) { for(var idx = 0; idx < fn.length; idx++) { this.stack.push(fn[idx]) } } else { this.stack.push(fn) } return this } /** * Adds a middleware function to the beginning of the internal route stack * @method module:skyring/lib/server/route#before * @param {module:skyring/lib/server/route~Middleware} fn a the middelware function to add **/ Route.prototype.before = function before(fn) { if (Array.isArray(fn)) { this.stack.unshift(...fn) } else { this.stack.unshift(fn) } return this } Route.prototype.match = function match(path) { const matches = this.regexp.exec(path) if (!matches) return null const keys = this.keys const params = Object.assign({}, this.params) for (var idx = 1; idx < matches.length; idx++) { params[keys[idx - 1]] = matches[idx] } return params } Route.prototype.process = function process(req, res, node, next) { const stack = this.stack ;(function run( idx ) { const fn = stack[idx] try { fn(req, res, node, (err, body) => { if ( err ) return next( err ) if( idx === stack.length -1 ) return next() run(++idx) }) } catch ( err ){ err.statusCode = err.statusCode || 500 return next( err ) } })(0) } module.exports = Route /** * A route middleware function * @typedef {Function} Middleware * @param {http.IncomingMessage} req The incomming request * @param {http.ServerResponse} res The response object to be sent * @param {module:skyring/lib/server/node} node The internal Ring Node instance * @param {Function} next The continuation callback to call when the middleware is finished **/