strong-error-handler 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +6 -0
- package/CHANGES.md +40 -0
- package/README.md +31 -26
- package/index.d.ts +1 -0
- package/lib/clone.js +7 -2
- package/lib/content-negotiation.js +13 -13
- package/lib/data-builder.js +4 -4
- package/lib/handler.js +14 -15
- package/lib/logger.js +5 -5
- package/lib/send-html.js +12 -12
- package/lib/send-json.js +10 -2
- package/lib/send-xml.js +8 -4
- package/package.json +13 -11
- package/test/handler.test.js +1016 -0
- package/views/default-error.ejs +1 -1
package/.travis.yml
ADDED
package/CHANGES.md
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
2020-10-13, Version 4.0.0
|
|
2
|
+
=========================
|
|
3
|
+
|
|
4
|
+
* docs: update LTS versions in README (Miroslav Bajtoš)
|
|
5
|
+
|
|
6
|
+
* [SEMVER-MAJOR] Reword log messages for clarity (Miroslav Bajtoš)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
2020-06-23, Version 3.5.0
|
|
10
|
+
=========================
|
|
11
|
+
|
|
12
|
+
* feat: add options.rootProperty for json/xml (Raymond Feng)
|
|
13
|
+
|
|
14
|
+
* chore: update deps and drop Node 8.x support (Raymond Feng)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
2019-10-12, Version 3.4.0
|
|
18
|
+
=========================
|
|
19
|
+
|
|
20
|
+
* chore: js2xmlparser to ^4.0.0 (Miroslav Bajtoš)
|
|
21
|
+
|
|
22
|
+
* chore: update dev-dependencies (mocha, supertest) (Miroslav Bajtoš)
|
|
23
|
+
|
|
24
|
+
* chore: update eslint & config to latest (Miroslav Bajtoš)
|
|
25
|
+
|
|
26
|
+
* chore: update strong-globalize to ^5.0.2 (Miroslav Bajtoš)
|
|
27
|
+
|
|
28
|
+
* chore: update debug to ^4.1.1 (Miroslav Bajtoš)
|
|
29
|
+
|
|
30
|
+
* feat: drop support for Node.js 6.x (Miroslav Bajtoš)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
2019-09-30, Version 3.3.0
|
|
34
|
+
=========================
|
|
35
|
+
|
|
36
|
+
* fix: handle Error objects with circular properties (dkrantsberg)
|
|
37
|
+
|
|
38
|
+
* chore: update copyrights years (Agnes Lin)
|
|
39
|
+
|
|
40
|
+
|
|
1
41
|
2018-08-30, Version 3.2.0
|
|
2
42
|
=========================
|
|
3
43
|
|
package/README.md
CHANGED
|
@@ -14,11 +14,15 @@ In debug mode, `strong-error-handler` returns full error stack traces and intern
|
|
|
14
14
|
|
|
15
15
|
## Supported versions
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
:-:|:-:|:-:
|
|
19
|
-
3.x|2.x|1.x
|
|
17
|
+
This module adopts the [Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy, with the following End Of Life (EOL) dates:
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
| Version | Status | Published | EOL |
|
|
20
|
+
| ---------- | --------------- | --------- | -------------------- |
|
|
21
|
+
| 4.x | Current | Oct 2020 | Apr 2023 _(minimum)_ |
|
|
22
|
+
| 3.x | Active LTS | Jun 2018 | Dec 2022 |
|
|
23
|
+
| 2.x | End-of-life | Mar 2017 | Oct 2020 |
|
|
24
|
+
|
|
25
|
+
Learn more about our LTS plan in the [LoopBack documentation](http://loopback.io/doc/en/contrib/Long-term-support.html).
|
|
22
26
|
|
|
23
27
|
## Installation
|
|
24
28
|
|
|
@@ -108,24 +112,25 @@ The content type of the response depends on the request's `Accepts` header.
|
|
|
108
112
|
|
|
109
113
|
## Options
|
|
110
114
|
|
|
111
|
-
| Option
|
|
112
|
-
|
|
|
113
|
-
| debug
|
|
114
|
-
| log
|
|
115
|
-
| safeFields
|
|
116
|
-
| defaultType
|
|
117
|
-
|
|
|
115
|
+
| Option | Type | Default | Description |
|
|
116
|
+
| -------------------- | ------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| 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. |
|
|
118
|
+
| 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). <br/> If `false`, sends only the error back in the response. |
|
|
119
|
+
| 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. |
|
|
120
|
+
| defaultType | String | `"json"` | Specifies the default response content type to use when the client does not provide any Accepts header. |
|
|
121
|
+
| rootProperty | String or false | `"error"` | Specifies the root property name for json or xml. If the value is set to `false`, no wrapper will be added to the json object. The false value is ignored by XML as a root element is always required. |
|
|
122
|
+
| negotiateContentType | Boolean | true | Negotiate the response content type via Accepts request header. When disabled, strong-error-handler will always use the default content type when producing responses. Disabling content type negotiation is useful if you want to see JSON-formatted error responses in browsers, because browsers usually prefer HTML and XML over other content types. |
|
|
118
123
|
|
|
119
124
|
### Customizing log format
|
|
120
125
|
|
|
121
|
-
**Express**
|
|
126
|
+
**Express**
|
|
122
127
|
|
|
123
|
-
To use a different log format, add your own custom error-handling middleware then disable `errorHandler.log`.
|
|
128
|
+
To use a different log format, add your own custom error-handling middleware then disable `errorHandler.log`.
|
|
124
129
|
For example, in an Express application:
|
|
125
130
|
|
|
126
131
|
```js
|
|
127
132
|
app.use(myErrorLogger());
|
|
128
|
-
app.use(errorHandler({
|
|
133
|
+
app.use(errorHandler({log: false}));
|
|
129
134
|
```
|
|
130
135
|
|
|
131
136
|
In general, add `strong-error-handler` as the last middleware function, just before calling `app.listen()`.
|
|
@@ -234,7 +239,7 @@ To migrate a LoopBack 2.x application to use `strong-error-handler`:
|
|
|
234
239
|
}
|
|
235
240
|
</pre>
|
|
236
241
|
|
|
237
|
-
For more information, see
|
|
242
|
+
For more information, see
|
|
238
243
|
[Migrating apps to LoopBack 3.0](http://loopback.io/doc/en/lb3/Migrating-to-3.0.html#update-use-of-rest-error-handler).
|
|
239
244
|
|
|
240
245
|
## Example
|
|
@@ -252,17 +257,17 @@ The same error generated when `debug: true` :
|
|
|
252
257
|
{ statusCode: 500,
|
|
253
258
|
name: 'Error',
|
|
254
259
|
message: 'a test error message',
|
|
255
|
-
stack: 'Error: a test error message
|
|
256
|
-
at Context.<anonymous> (User/strong-error-handler/test/handler.test.js:220:21)
|
|
257
|
-
at callFnAsync (User/strong-error-handler/node_modules/mocha/lib/runnable.js:349:8)
|
|
258
|
-
at Test.Runnable.run (User/strong-error-handler/node_modules/mocha/lib/runnable.js:301:7)
|
|
259
|
-
at Runner.runTest (User/strong-error-handler/node_modules/mocha/lib/runner.js:422:10)
|
|
260
|
-
at User/strong-error-handler/node_modules/mocha/lib/runner.js:528:12
|
|
261
|
-
at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:342:14)
|
|
262
|
-
at User/strong-error-handler/node_modules/mocha/lib/runner.js:352:7
|
|
263
|
-
at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:284:14)
|
|
264
|
-
at Immediate._onImmediate (User/strong-error-handler/node_modules/mocha/lib/runner.js:320:5)
|
|
265
|
-
at tryOnImmediate (timers.js:543:15)
|
|
260
|
+
stack: 'Error: a test error message
|
|
261
|
+
at Context.<anonymous> (User/strong-error-handler/test/handler.test.js:220:21)
|
|
262
|
+
at callFnAsync (User/strong-error-handler/node_modules/mocha/lib/runnable.js:349:8)
|
|
263
|
+
at Test.Runnable.run (User/strong-error-handler/node_modules/mocha/lib/runnable.js:301:7)
|
|
264
|
+
at Runner.runTest (User/strong-error-handler/node_modules/mocha/lib/runner.js:422:10)
|
|
265
|
+
at User/strong-error-handler/node_modules/mocha/lib/runner.js:528:12
|
|
266
|
+
at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:342:14)
|
|
267
|
+
at User/strong-error-handler/node_modules/mocha/lib/runner.js:352:7
|
|
268
|
+
at next (User/strong-error-handler/node_modules/mocha/lib/runner.js:284:14)
|
|
269
|
+
at Immediate._onImmediate (User/strong-error-handler/node_modules/mocha/lib/runner.js:320:5)
|
|
270
|
+
at tryOnImmediate (timers.js:543:15)
|
|
266
271
|
at processImmediate [as _immediateCallback] (timers.js:523:5)' }}
|
|
267
272
|
```
|
|
268
273
|
|
package/index.d.ts
CHANGED
package/lib/clone.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2016. All Rights Reserved.
|
|
2
|
+
// Node module: strong-error-handler
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
1
6
|
'use strict';
|
|
2
7
|
module.exports = cloneAllProperties;
|
|
3
8
|
|
|
@@ -10,10 +15,10 @@ module.exports = cloneAllProperties;
|
|
|
10
15
|
function cloneAllProperties(data, err) {
|
|
11
16
|
data.name = err.name;
|
|
12
17
|
data.message = err.message;
|
|
13
|
-
for (
|
|
18
|
+
for (const p in err) {
|
|
14
19
|
if ((p in data)) continue;
|
|
15
20
|
data[p] = err[p];
|
|
16
21
|
}
|
|
17
22
|
// stack is appended last to ensure order is the same for response
|
|
18
23
|
data.stack = err.stack;
|
|
19
|
-
}
|
|
24
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2016. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
|
|
2
2
|
// Node module: strong-error-handler
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const accepts = require('accepts');
|
|
8
|
+
const debug = require('debug')('strong-error-handler:http-response');
|
|
9
|
+
const sendJson = require('./send-json');
|
|
10
|
+
const sendHtml = require('./send-html');
|
|
11
|
+
const sendXml = require('./send-xml');
|
|
12
|
+
const util = require('util');
|
|
13
13
|
|
|
14
14
|
module.exports = negotiateContentProducer;
|
|
15
15
|
|
|
@@ -23,14 +23,14 @@ module.exports = negotiateContentProducer;
|
|
|
23
23
|
* @returns {Function} Operation function with signature `fn(res, data)`
|
|
24
24
|
*/
|
|
25
25
|
function negotiateContentProducer(req, logWarning, options) {
|
|
26
|
-
|
|
26
|
+
const SUPPORTED_TYPES = [
|
|
27
27
|
'application/json', 'json',
|
|
28
28
|
'text/html', 'html',
|
|
29
29
|
'text/xml', 'xml',
|
|
30
30
|
];
|
|
31
31
|
|
|
32
32
|
options = options || {};
|
|
33
|
-
|
|
33
|
+
let defaultType = 'json';
|
|
34
34
|
|
|
35
35
|
// checking if user provided defaultType is supported
|
|
36
36
|
if (options.defaultType) {
|
|
@@ -52,9 +52,9 @@ function negotiateContentProducer(req, logWarning, options) {
|
|
|
52
52
|
// Accepts: */*, application/json, text/html ---> will resolve as application/json
|
|
53
53
|
// eg. Chrome accepts defaults to `text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*`
|
|
54
54
|
// In this case `resolvedContentType` will result as: `text/html` due to the order given
|
|
55
|
-
|
|
55
|
+
const resolvedContentType = accepts(req).types(SUPPORTED_TYPES);
|
|
56
56
|
debug('Resolved content-type', resolvedContentType);
|
|
57
|
-
|
|
57
|
+
let contentType = resolvedContentType || defaultType;
|
|
58
58
|
|
|
59
59
|
if (options.negotiateContentType === false) {
|
|
60
60
|
if (SUPPORTED_TYPES.indexOf(options.defaultType) > -1) {
|
|
@@ -71,13 +71,13 @@ function negotiateContentProducer(req, logWarning, options) {
|
|
|
71
71
|
// to receive _format from user's url param to overide the content type
|
|
72
72
|
// req.query (eg /api/Users/1?_format=json will overide content negotiation
|
|
73
73
|
// https://github.com/strongloop/strong-remoting/blob/ac3093dcfbb787977ca0229b0f672703859e52e1/lib/http-context.js#L643-L645
|
|
74
|
-
|
|
74
|
+
const query = req.query || {};
|
|
75
75
|
if (query._format) {
|
|
76
76
|
if (SUPPORTED_TYPES.indexOf(query._format) > -1) {
|
|
77
77
|
contentType = query._format;
|
|
78
78
|
} else {
|
|
79
79
|
// format passed through query but not supported
|
|
80
|
-
|
|
80
|
+
const msg = util.format('Response _format "%s" is not supported' +
|
|
81
81
|
'used "%s" instead"', query._format, defaultType);
|
|
82
82
|
logWarning(msg);
|
|
83
83
|
}
|
package/lib/data-builder.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2016. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
|
|
2
2
|
// Node module: strong-error-handler
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const cloneAllProperties = require('../lib/clone.js');
|
|
9
|
+
const httpStatus = require('http-status');
|
|
10
10
|
|
|
11
11
|
module.exports = buildResponseData;
|
|
12
12
|
|
|
@@ -44,7 +44,7 @@ function buildResponseData(err, options) {
|
|
|
44
44
|
fillSafeFields(data, err, safeFields);
|
|
45
45
|
|
|
46
46
|
return data;
|
|
47
|
-
}
|
|
47
|
+
}
|
|
48
48
|
|
|
49
49
|
function serializeArrayOfErrors(errors, options) {
|
|
50
50
|
const details = errors.map(e => buildResponseData(e, options));
|
package/lib/handler.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2016. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
|
|
2
2
|
// Node module: strong-error-handler
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const SG = require('strong-globalize');
|
|
10
10
|
SG.SetRootDir(path.resolve(__dirname, '..'));
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var negotiateContentProducer = require('./content-negotiation');
|
|
11
|
+
const buildResponseData = require('./data-builder');
|
|
12
|
+
const debug = require('debug')('strong-error-handler');
|
|
13
|
+
const logToConsole = require('./logger');
|
|
14
|
+
const negotiateContentProducer = require('./content-negotiation');
|
|
16
15
|
|
|
17
16
|
function noop() {
|
|
18
17
|
}
|
|
@@ -29,13 +28,13 @@ function createStrongErrorHandler(options) {
|
|
|
29
28
|
debug('Initializing with options %j', options);
|
|
30
29
|
|
|
31
30
|
// Log all errors via console.error (enabled by default)
|
|
32
|
-
|
|
31
|
+
const logError = options.log !== false ? logToConsole : noop;
|
|
33
32
|
|
|
34
33
|
return function strongErrorHandler(err, req, res, next) {
|
|
35
34
|
logError(req, err);
|
|
36
35
|
writeErrorToResponse(err, req, res, options);
|
|
37
36
|
};
|
|
38
|
-
}
|
|
37
|
+
}
|
|
39
38
|
|
|
40
39
|
/**
|
|
41
40
|
* Writes thrown error to response
|
|
@@ -50,7 +49,7 @@ function writeErrorToResponse(err, req, res, options) {
|
|
|
50
49
|
|
|
51
50
|
options = options || {};
|
|
52
51
|
|
|
53
|
-
if (res.
|
|
52
|
+
if (res.headersSent) {
|
|
54
53
|
debug('Response was already sent, closing the underlying connection');
|
|
55
54
|
return req.socket.destroy();
|
|
56
55
|
}
|
|
@@ -59,20 +58,20 @@ function writeErrorToResponse(err, req, res, options) {
|
|
|
59
58
|
if (!err.status && !err.statusCode && res.statusCode >= 400)
|
|
60
59
|
err.statusCode = res.statusCode;
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
const data = buildResponseData(err, options);
|
|
63
62
|
debug('Response status %s data %j', data.statusCode, data);
|
|
64
63
|
|
|
65
64
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
66
65
|
res.statusCode = data.statusCode;
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
sendResponse(res, data);
|
|
67
|
+
const sendResponse = negotiateContentProducer(req, warn, options);
|
|
68
|
+
sendResponse(res, data, options);
|
|
70
69
|
|
|
71
70
|
function warn(msg) {
|
|
72
71
|
res.header('X-Warning', msg);
|
|
73
72
|
debug(msg);
|
|
74
73
|
}
|
|
75
|
-
}
|
|
74
|
+
}
|
|
76
75
|
|
|
77
76
|
exports = module.exports = createStrongErrorHandler;
|
|
78
77
|
exports.writeErrorToResponse = writeErrorToResponse;
|
package/lib/logger.js
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const format = require('util').format;
|
|
9
|
+
const g = require('strong-globalize')();
|
|
10
10
|
|
|
11
11
|
module.exports = function logToConsole(req, err) {
|
|
12
12
|
if (!Array.isArray(err)) {
|
|
13
|
-
g.error('
|
|
13
|
+
g.error('Request %s %s failed: %s',
|
|
14
14
|
req.method, req.url, err.stack || err);
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const errMsg = g.f('Request %s %s failed with multiple errors:\n',
|
|
19
19
|
req.method, req.url);
|
|
20
|
-
|
|
20
|
+
const errors = err.map(formatError).join('\n');
|
|
21
21
|
console.error(errMsg, errors);
|
|
22
22
|
};
|
|
23
23
|
|
package/lib/send-html.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const ejs = require('ejs');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const assetDir = path.resolve(__dirname, '../views');
|
|
12
|
+
const compiledTemplates = {
|
|
13
13
|
// loading default template and stylesheet
|
|
14
14
|
default: loadDefaultTemplates(),
|
|
15
15
|
};
|
|
@@ -17,10 +17,10 @@ var compiledTemplates = {
|
|
|
17
17
|
module.exports = sendHtml;
|
|
18
18
|
|
|
19
19
|
function sendHtml(res, data, options) {
|
|
20
|
-
|
|
20
|
+
const toRender = {options, data};
|
|
21
21
|
// TODO: ability to call non-default template functions from options
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const body = compiledTemplates.default(toRender);
|
|
23
|
+
sendResponse(res, body);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -30,18 +30,18 @@ function sendHtml(res, data, options) {
|
|
|
30
30
|
* @returns {Function} render function with signature fn(data);
|
|
31
31
|
*/
|
|
32
32
|
function compileTemplate(filepath) {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const options = {cache: true, filename: filepath};
|
|
34
|
+
const fileContent = fs.readFileSync(filepath, 'utf8');
|
|
35
35
|
return ejs.compile(fileContent, options);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// loads and cache default error templates
|
|
39
39
|
function loadDefaultTemplates() {
|
|
40
|
-
|
|
40
|
+
const defaultTemplate = path.resolve(assetDir, 'default-error.ejs');
|
|
41
41
|
return compileTemplate(defaultTemplate);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function
|
|
44
|
+
function sendResponse(res, body) {
|
|
45
45
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
46
46
|
res.end(body);
|
|
47
47
|
}
|
package/lib/send-json.js
CHANGED
|
@@ -5,8 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const safeStringify = require('fast-safe-stringify');
|
|
9
|
+
|
|
10
|
+
module.exports = function sendJson(res, data, options) {
|
|
11
|
+
options = options || {};
|
|
12
|
+
// Set `options.rootProperty` to not wrap the data into an `error` object
|
|
13
|
+
const err = options.rootProperty === false ? data : {
|
|
14
|
+
// Use `options.rootProperty`, if not set, default to `error`
|
|
15
|
+
[options.rootProperty || 'error']: data,
|
|
16
|
+
};
|
|
17
|
+
const content = safeStringify(err);
|
|
10
18
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
11
19
|
res.end(content, 'utf-8');
|
|
12
20
|
};
|
package/lib/send-xml.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
// Copyright IBM Corp.
|
|
1
|
+
// Copyright IBM Corp. 2017. All Rights Reserved.
|
|
2
2
|
// Node module: strong-error-handler
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const js2xmlparser = require('js2xmlparser');
|
|
9
9
|
|
|
10
|
-
module.exports = function sendXml(res, data) {
|
|
11
|
-
|
|
10
|
+
module.exports = function sendXml(res, data, options) {
|
|
11
|
+
options = options || {};
|
|
12
|
+
// Xml always requires a root element.
|
|
13
|
+
// `options.rootProperty === false` is not honored
|
|
14
|
+
const root = options.rootProperty || 'error';
|
|
15
|
+
const content = js2xmlparser.parse(root, data);
|
|
12
16
|
res.setHeader('Content-Type', 'text/xml; charset=utf-8');
|
|
13
17
|
res.end(content, 'utf-8');
|
|
14
18
|
};
|
package/package.json
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"name": "strong-error-handler",
|
|
3
3
|
"description": "Error handler for use in development and production environments.",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "4.0.0",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=10"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -19,19 +19,20 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@types/express": "^4.16.0",
|
|
21
21
|
"accepts": "^1.3.3",
|
|
22
|
-
"debug": "^
|
|
23
|
-
"ejs": "^
|
|
22
|
+
"debug": "^4.1.1",
|
|
23
|
+
"ejs": "^3.1.3",
|
|
24
|
+
"fast-safe-stringify": "^2.0.6",
|
|
24
25
|
"http-status": "^1.1.2",
|
|
25
|
-
"js2xmlparser": "^
|
|
26
|
-
"strong-globalize": "^
|
|
26
|
+
"js2xmlparser": "^4.0.0",
|
|
27
|
+
"strong-globalize": "^6.0.1"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"chai": "^4.1.2",
|
|
30
|
-
"eslint": "^
|
|
31
|
-
"eslint-config-loopback": "^
|
|
31
|
+
"eslint": "^7.0.0",
|
|
32
|
+
"eslint-config-loopback": "^13.1.0",
|
|
32
33
|
"express": "^4.16.3",
|
|
33
|
-
"mocha": "^
|
|
34
|
-
"supertest": "^
|
|
34
|
+
"mocha": "^7.1.2",
|
|
35
|
+
"supertest": "^4.0.2"
|
|
35
36
|
},
|
|
36
37
|
"browser": {
|
|
37
38
|
"strong-error-handler": false
|
|
@@ -40,5 +41,6 @@
|
|
|
40
41
|
"downstreamIgnoreList": [
|
|
41
42
|
"dashboard-controller"
|
|
42
43
|
]
|
|
43
|
-
}
|
|
44
|
+
},
|
|
45
|
+
"author": "IBM Corp."
|
|
44
46
|
}
|