UNPKG

express-respond

Version:

HTTP response methods with auto content negotiation for expressjs

139 lines (122 loc) 3.96 kB
'use strict'; const _ = require('lodash'); const common = require('@lykmapipo/common'); const env = require('@lykmapipo/env'); // TODO: just extend response directly /** * @function prepareBody * @name prepareBody * @description prepare response body * @param {*} [data] valid response body * @param {string} [code=500] valid http response status code * @returns {object} formatted response body * @author lally elias <lallyelias87@mail.com> * @since 1.1.0 * @version 0.1.0 * @license MIT * @private * @example * const body = prepareBody(new Error('Missing API Key')); * //=> { message: 'Missing API Key', ... } * * const body = prepareBody({ name: 'lykmapipo' }); * //=> { name: 'lykmapipo' } */ const prepareBody = (data, code = 500) => { // build response base on http status code if (!data) { const status = code; const message = common.STATUS_CODES[code]; const description = common.STATUS_CODES[code]; return { status, code, message, description }; } // handle error or data const stack = !env.isProduction(); let body = {}; body = _.isError(data) ? common.mapErrorToObject(data, { code, stack }) : data; // return formatted response body return body; }; /** * @function mapToHttpReply * @name mapToHttpReply * @description generate http reply method based on http status * @param {object} response valid express http response object * @param {string} code valid http response status code * @returns {Function} a valid response function helper * @author lally elias <lallyelias87@mail.com> * @since 1.2.0 * @version 0.1.0 * @license MIT * @private */ const mapToHttpReply = (response, code) => (data) => { // prepare http status let status = _.get(data, 'status', code); // FIX: RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code // FIX: if response data has status field for business logics status = _.isNumber(status) || _.isString(status) ? status : code; // set response status response.status(status); // respond with json body const ignoreBody = _.includes([204, 304], _.toNumber(status)); if (ignoreBody) { return response.json(); } // prepare response body const body = prepareBody(data, status); return response.json(body); }; /** * @function mapStatusToMethod * @name mapStatusToMethod * @description map http status to named response method * @param {object} response valid express http response object * @returns {Function} a valid response function helper * @author lally elias <lallyelias87@mail.com> * @since 1.2.0 * @version 0.1.0 * @license MIT * @private */ const mapStatusToMethod = (response) => (status, code) => { // prepare response method from http status message const method = _.camelCase(status); // extend http response with the custom response type method const httpReply = mapToHttpReply(response, code); response[code] = httpReply; response[method] = httpReply; }; /** * @function respond * @name respond * @description common http responses for expressjs * @param {object} request valid express http request object * @param {object} response valid express http response object * @param {Function} next a middleware to invoke for continuation * @returns {Function} a valid expressjs middleware * @author lally elias <lallyelias87@mail.com> * @since 1.0.0 * @version 0.1.0 * @license MIT * @public * @example * const express = require('express'); * const respond = require('express-respond'); * * const app = express(); * app.use(respond); * * app.get('/', (request, response) => { * response.ok({ name: 'lykmapipo' }); * }); */ const respond = (request, response, next) => { // map http status code to http response method _.forEach(common.STATUS_CODES, mapStatusToMethod(response)); // add error response method response.error = mapToHttpReply(response, 500); // continue with middleware chain return next(); }; module.exports = respond;