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