Source: adapters/json_content.js

'use strict';
const Promisie = require('promisie');

/**
 * Creates a formatted success response object
 * @param  {*}  data    Any data that should be sent with the success response
 * @param  {Object} options Configurable options for success response formatting
 * @param {Function} [options.formatRender=this.formatRender] Custom formatting function for json success response. This argument will be ignored if not a function
 * @return {Object}         Formatted success response object
 */
const _RENDER = function (data, options) {
	if (typeof this.formatRender === 'function' || typeof options.formatRender === 'function') return (typeof options.formatRender === 'function') ? options.formatRender(data, options) : this.formatRender(data, options);
	else {
		return {
			result: 'success',
			status: 200,
			data
		};
	}
};

/**
 * Creates a formatted error response object
 * @param  {*}  err     Any data to be sent as part of error response
 * @param  {Object} options Configurable options for error response formatting
 * @param {Function} [options.formatError=this.formatError] Custom formatting function for json error response. This argument will be ignored if not a function
 * @return {Object}         Formatted error response object
 */
const _ERROR = function (data, options) {
	if (typeof this.formatError === 'function' || typeof options.formatError === 'function') return (typeof options.formatError === 'function') ? options.formatError(data, options) : this.formatError(data, options);
	else {
		return {
			result: 'error',
			status: 500,
			data: {
				error: data
			}
		};
	}
};

/**
 * Baseline adapter class which handles wrapping response data in an object with a status code and result message. Formatting is configurable both for success and error responses
 * @type {JSON_Adapter}
 */
const JSON_ADAPTER = class JSON_Adapter {
	/**
	 * @constructor
	 * @param  {Object} [options={}] Configurable options for the adapter
	 * @param {Function} options.formatRender Overwrites default formatting behavior for json responses
	 * @param {Function} options.formatError Overwrites default formatting behavior for errors
	 */
	constructor (options = {}) {
		this.formatRender = options.formatRender;
		this.formatError = options.formatError;
	}
	/**
	 * Creates a formatted response
	 * @param  {*}  data    Any data that should be sent with the success response
	 * @param  {Object}  [options={}] Configurable options for success response formatting see _RENDER for more details
	 * @param {Object} [options.req] Express request object. If options.req and options.res are defined the express .render method will be used to render template
	 * @param {Object} [options.res] Express response object. If options.res and options.req are defined the express .render method will be used to render template
	 * @param {Boolean} [options.skip_response] If true function will resolve with the rendered template instead of sending a response
	 * @param {Boolean} options.sync If true execution of render will be handled synchronously
	 * @param  {Function} [cb=false]      An optional callback function. If this argument is not a function it will be ignored
	 * @return {*}          Returns the formatted json object if options.sync is true or a Promise if cb arugement is not passed
	 */
	render (data, options = {}, cb = false) {
		try {
			if (typeof options === 'function') {
				cb = options;
				options = {};
			}
			let rendered = _RENDER.call(this, data, options);
			if (options.req && options.res && !options.skip_response) {
				if (options.req.query && options.req.query.callback) options.res.status(200).jsonp(rendered);
				else options.res.status(200).send(rendered);
			}
			if (options.sync !== true) {
				if (typeof cb === 'function') cb(null, rendered);
				else return Promisie.resolve(rendered);
			}
			else return rendered;
		}
		catch (e) {
			return this.error(e, options, cb);
		}
	}
	/**
	 * Creates a formatted error response
	 * @param  {*}  err     Any data to be sent as part of error response
	 * @param  {Object}  options Configurable options for error response formatting see _ERROR for more details
	 * @param {Boolean} options.sync If ture execution of error will be handled synchronously
	 * @param {Object} [options.req] Express request object. If options.req and options.res are defined the express .render method will be used to render template
	 * @param {Object} [options.res] Express response object. If options.res and options.req are defined the express .render method will be used to render template
	 * @param {Boolean} [options.skip_response] If true function will resolve with the rendered template instead of sending a response
	 * @param  {Function} [cb=false]      An optional callback function. If this argument is not a function it will be ignored
 	 * @return {*}          Returns the formatted json object if options.sync is true or a Promise if cb arugement is not passed
	 */
	error (err, options = {}, cb = false) {
		try {
			if (typeof options === 'function') {
				cb = options;
				options = {};
			}
			let errored = _ERROR.call(this, err, options);
			if (options.req && options.res && !options.skip_response) {
				if (options.req.query && options.req.query.callback) options.res.status(500).jsonp(errored);
				else options.res.status(500).send(errored);
			}
			if (options.sync !== true) {
				if (typeof cb === 'function') cb(null, errored);
				else return Promisie.resolve(errored);
			}
			else return errored;
		}
		catch (e) {
			if (options.sync !== true) {
				if (typeof cb === 'function') cb(e);
				else return Promisie.reject(e);
			}
			else throw e;
		}
	}
};

module.exports = JSON_ADAPTER;