diff --git a/README.md b/README.md index deb8fb9d..fe4ec989 100644 --- a/README.md +++ b/README.md @@ -82,12 +82,15 @@ The content type of the response depends on the request's `Accepts` header. | debug | Boolean    | `false` | If `true`, HTTP responses include all error properties, including sensitive data such as file paths, URLs and stack traces. See [Example output](#example) below. | | log | Boolean | `true` | If `true`, all errors are printed via `console.error`, including an array of fields (custom error properties) that are safe to include in response messages (both 4xx and 5xx).
If `false`, sends only the error back in the response. | | safeFields | [String] | `[]` | Specifies property names on errors that are allowed to be passed through in 4xx and 5xx responses. See [Safe error fields](#safe-error-fields) below. | +| jsonRenderer | String | 'send-json' | Operation function to render JSON with signature `fn(res, data)`. Defaults to `./send-json` (`lib/send-json.js`). | +| htmlRenderer | String | 'send-html' | Operation function to render HTML with signature `fn(res, data)`. Defaults to `./send-html` (`lib/send-html.js`). | +| xmlRenderer | String | 'send-xml' | Operation function to render XML with signature `fn(res, data)`. Defaults to `./send-xml` (`lib/send-xml.js`). | ### Customizing log format -**Express** +**Express** -To use a different log format, add your own custom error-handling middleware then disable `errorHandler.log`. +To use a different log format, add your own custom error-handling middleware then disable `errorHandler.log`. For example, in an Express application: ```js @@ -155,6 +158,34 @@ Using the above configuration, an error containing an `errorCode` property will } ``` +### Custom Renderer Functions + +You can switch out the default renderers for HTML, JSON, and XML responses with custom renderers: + +``` +{ + // ... + "final:after": { + "strong-error-handler": { + "params": { + "htmlRenderer": "$!./lib/send-html" + } + } +} +``` + +The `$!` characters indicate that the path is relative to the location of `middleware.json`. + +*./lib/send-html.js:* + +``` +module.exports = function(res, data) { + res.send("Hello."); +} +``` + +Using the above configuration, a request with `Content-type: text/html` that is handled by strong-error-handler will return a `Content-type: text/html` and a response body of `Hello.`. + ## Migration from old LoopBack error handler NOTE: This is only required for applications scaffolded with old versions of the `slc loopback` tool. @@ -201,7 +232,7 @@ To migrate a LoopBack 2.x application to use `strong-error-handler`: } -For more information, see +For more information, see [Migrating apps to LoopBack 3.0](http://loopback.io/doc/en/lb3/Migrating-to-3.0.html#update-use-of-rest-error-handler). ## Example @@ -219,17 +250,17 @@ The same error generated when `debug: true` : { statusCode: 500, name: 'Error', message: 'a test error message', - stack: 'Error: a test error message - at Context. (User/strong-error-handler/test/handler.test.js:220:21) - at callFnAsync (User/strong-error-handler/node_modules/mocha/lib/runnable.js:349:8) - at Test.Runnable.run (User/strong-error-handler/node_modules/mocha/lib/runnable.js:301:7) - at Runner.runTest (User/strong-error-handler/node_modules/mocha/lib/runner.js:422:10) - at User/strong-error-handler/node_modules/mocha/lib/runner.js:528:12 - at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:342:14) - at User/strong-error-handler/node_modules/mocha/lib/runner.js:352:7 - at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:284:14) - at Immediate._onImmediate (User/strong-error-handler/node_modules/mocha/lib/runner.js:320:5) - at tryOnImmediate (timers.js:543:15) + stack: 'Error: a test error message + at Context. (User/strong-error-handler/test/handler.test.js:220:21) + at callFnAsync (User/strong-error-handler/node_modules/mocha/lib/runnable.js:349:8) + at Test.Runnable.run (User/strong-error-handler/node_modules/mocha/lib/runnable.js:301:7) + at Runner.runTest (User/strong-error-handler/node_modules/mocha/lib/runner.js:422:10) + at User/strong-error-handler/node_modules/mocha/lib/runner.js:528:12 + at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:342:14) + at User/strong-error-handler/node_modules/mocha/lib/runner.js:352:7 + at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:284:14) + at Immediate._onImmediate (User/strong-error-handler/node_modules/mocha/lib/runner.js:320:5) + at tryOnImmediate (timers.js:543:15) at processImmediate [as _immediateCallback] (timers.js:523:5)' }} ``` diff --git a/lib/content-negotiation.js b/lib/content-negotiation.js index 21ff9e43..2e8663fe 100644 --- a/lib/content-negotiation.js +++ b/lib/content-negotiation.js @@ -6,11 +6,12 @@ 'use strict'; var accepts = require('accepts'); var debug = require('debug')('strong-error-handler:http-response'); -var sendJson = require('./send-json'); -var sendHtml = require('./send-html'); -var sendXml = require('./send-xml'); var util = require('util'); +var sendJson; +var sendHtml; +var sendXml; + module.exports = negotiateContentProducer; /** @@ -20,9 +21,9 @@ module.exports = negotiateContentProducer; * @param req request object * @param {Object} options options of strong-error-handler * @param {Function} logWarning a logger function for reporting warnings - * @returns {Function} Opeartion function with signature `fn(res, data)` + * @returns {Function} Operation function with signature `fn(res, data)` */ -function negotiateContentProducer(req, logWarning, options) { +function negotiateContentProducer(req, options, logWarning) { var SUPPORTED_TYPES = [ 'application/json', 'json', 'text/html', 'html', @@ -43,6 +44,25 @@ function negotiateContentProducer(req, logWarning, options) { } } + // resolve renderer functions + if (!('jsonRenderer' in options)) { + options.jsonRenderer = './send-json'; + } + + sendJson = require(options.jsonRenderer); + + if (!('htmlRenderer' in options)) { + options.htmlRenderer = './send-html'; + } + + sendHtml = require(options.htmlRenderer); + + if (!('xmlRenderer' in options)) { + options.xmlRenderer = './send-xml'; + } + + sendXml = require(options.xmlRenderer); + // decide to use resolvedType or defaultType // Please note that accepts assumes the order of content-type is provided // in the priority returned