Skip to content

Instantly share code, notes, and snippets.

@cravindra
Created November 7, 2017 11:48
Show Gist options
  • Save cravindra/e634dc68e089dc66e2316443a5773d8e to your computer and use it in GitHub Desktop.
Save cravindra/e634dc68e089dc66e2316443a5773d8e to your computer and use it in GitHub Desktop.
Express Middleware to augment the Request and Response Object with some helpful methods and attributes
/**
* Middleware to add the following helpers to the req object
* 1. wantsJSON
* 2. getAllParams
* @param req - The Express Request Object for the current request
* @param res - The Express Response Object for the current request
* @param next
*/
function enhanceReq(req, res, next) {
/**
* True if this request is an XHR Request or contains 'json' in it's 'accept' header
* @type {boolean}
*/
req.wantsJSON = req.xhr || req.headers.accept.indexOf('json') > -1;
/**
* Helper to get all parameters available in the headers, query string, request body and the url route parameters.
* @returns {Object} mergedParameters - A map of all available parameters
*/
function getAllParams(){
return _.merge({}, req.headers, req.query, req.body, req.params);
}
req.params.all = getAllParams;
next();
};
module.exports = enhanceReq;
const _ = require('lodash');
const utils = require('../../services/application/utils');
/**
* Middleware which adds the following methods to the res object:
* 1. res.render
* 2. res.ok
* 3. res.badRequest
* 4. res.serverError
* 5. res.notFound
* 6. res.error
* 7. res.forbidden
*
* @param req - The Express Request Object for the current request
* @param res - The Express Response Object for the current request
* @param next
*/
function enhanceRes(req, res, next) {
/**
* Helper to render a template and handle any render errors if needed
* @param template {string} The name of the template to be rendered
* @param data {Object} The data to be passed to the template
*/
function renderTemplate(template, data) {
let PATH = '../../src/templates/';
data = data || {};
req.config = _.merge({}, config);
try {
let tmpl = require(PATH + template);
res.marko(tmpl, data);
}
catch (e) {
req.log.error({
code: 500,
message: 'Template Render Error',
template: template,
data: data,
error: e
});
res.serverError({
message: 'Render error'
});
}
}
/**
* Helper to respond with a generic error. Sends JSON if it's AJAX else renders the error template
* @param statusCode {int} HTTP Status code to send the error with
* @param {Object} [error] The error object
*/
function sendError(statusCode, error) {
res.status(statusCode);
error.message = utils.translate(req, error.message);
let err = {
code: statusCode,
message: error.message,
data: error
};
if (req.wantsJSON) {
//AJAX request. Respond with JSON
res.json(err);
} else {
//Browser request. Render Error Template
res.render('error', err);
}
}
/**
* Helper to send a 404 not found response
* @param {Object} [error] The error object
*/
function send404(error) {
error = error || {};
error.message = error.message || 'error.send404Error';
sendError(404, error);
}
/**
* Helper to send a 503 server error response
* @param {Object} [error] The error object
*/
function send503(error) {
error = error || {};
error.message = error.message || 'error.send503Error';
sendError(503, error);
}
/**
* Helper to send a 400 bad request response
* @param {Object} [error] The error object
*/
function send400(error) {
error = error || {};
error.message = error.message || 'error.send400Error';
sendError(503, error);
}
/**
* Helper to send a 403 forbidden response
* @param {Object} [error] The error object
*/
function send403(error) {
error = error || {};
error.message = error.message || 'error.send403Error';
sendError(403, error);
}
/**
* Helper to send a 200 ok response
* If a query parameter `pretty=true` exists, this pretty prints the JSON
* @param data {Object} The data to send as a response
*/
function send200(data) {
res.status(200);
if (req.query.pretty === 'true') {
res.header('Content-Type', 'application/json');
res.send(JSON.stringify(data, null, 4));
} else {
res.json(data);
}
}
/**
* Helper to redirect with the ui query parameter as needed based on if this is a cookie less call
* @param {string} [url] Optional URL to redirect to. Defaults to the same URL as the current request if no url is provided
* @param {Object} [query] Optional dictionary of key - value pairs to add to the query string
*/
function slRedirect(url, query) {
query = query || {};
//If this is a cookie less flow, add the session ID as a query parameter
if(req.session.cookieless && req.sessionID){
query.uid = req.sessionID;
}
if (!url) {
//No URL Parameter Get Current Path and Query parameters and use that
url = req.originalUrl.split('?')[0];
query = _.merge({}, req.query, query);
} else {
//URL is provided. Parse the query and rebuild if query parameters are provided
let qp = utils.parseQueryParameters(url);
query = _.merge({}, qp, query);
url = url.split('?')[0];
}
//Build new query string
let queryString = Object.keys(query).reduce(function (m, key, i, list) {
m += key + '=' + query[key] + ((i < (list.length - 1)) ? '&' : '');
return m;
}, '?');
res.redirect(queryString.length > 1 ? url + queryString : url);
}
//Load Auxiliary Response functions
res.render = renderTemplate;
res.error = sendError;
res.notFound = send404;
res.serverError = send503;
res.badRequest = send400;
res.forbidden = send403;
res.ok = send200;
next();
}
module.exports = enhanceRes;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment