Add type definition and writeErrorToResponse

This commit is contained in:
shimks 2018-08-08 13:28:45 -04:00
parent 8b35494da0
commit 80ebf30cfa
5 changed files with 139 additions and 38 deletions

View File

@ -46,6 +46,29 @@ app.use(errorHandler({
app.listen(3000);
```
The module also exports `writeErrorToResponse`, a non-middleware flavor of the
error handler:
```js
const http = require('http');
const writeErrorToResponse = require('strong-error-handler')
.writeErrorToResponse;
const errHandlingOptions = {debug: process.env.NODE_ENV === 'development'}
http
.createServer((req, res) => {
if (errShouldBeThrown) {
writeErrorToResponse(
new Error('something went wrong'),
req,
res,
errHandlingOptions,
);
}
})
.listen(3000);
```
In LoopBack applications, add the following entry to `server/middleware.json`:
```json

64
index.d.ts vendored Normal file
View File

@ -0,0 +1,64 @@
// Copyright IBM Corp. 2018. All Rights Reserved.
// Node module: strong-error-handler
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
// Type definitions for strong-error-handler 3.x
// Project: https://github.com/strongloop/strong-error-handler
// Definitions by: Kyusung Shim <https://github.com/shimks>
// TypeScript Version: 3.0
import * as Express from 'express';
export = errorHandlerFactory;
/**
* Creates a middleware function for error-handling
* @param options Options for error handler settings
*/
declare function errorHandlerFactory(
options?: errorHandlerFactory.ErrorHandlerOptions
): errorHandlerFactory.StrongErrorHandler;
declare namespace errorHandlerFactory {
/**
* Writes thrown error to response
* @param err Error to handle
* @param req Incoming request
* @param res Response
* @param options Options for error handler settings
*/
function writeErrorToResponse(
err: Error,
req: Express.Request,
res: Express.Response,
options?: ErrorWriterOptions
): void;
/**
* Error-handling middleware function. Includes server-side logging
*/
type StrongErrorHandler = (
err: Error,
req: Express.Request,
res: Express.Response,
next: (err?: any) => void
) => void;
/**
* Options for writing errors to the response
*/
interface ErrorWriterOptions {
debug?: boolean;
safeFields?: string[];
defaultType?: string;
negotiateContentType?: boolean;
}
/**
* Options for error-handling
*/
interface ErrorHandlerOptions extends ErrorWriterOptions {
log?: boolean;
}
}

View File

@ -23,7 +23,7 @@ function noop() {
* @param {Object} options
* @returns {Function}
*/
exports = module.exports = function createStrongErrorHandler(options) {
function createStrongErrorHandler(options) {
options = options || {};
debug('Initializing with options %j', options);
@ -32,31 +32,47 @@ exports = module.exports = function createStrongErrorHandler(options) {
var logError = options.log !== false ? logToConsole : noop;
return function strongErrorHandler(err, req, res, next) {
debug('Handling %s', err.stack || err);
logError(req, err);
if (res._header) {
debug('Response was already sent, closing the underlying connection');
return req.socket.destroy();
}
// this will alter the err object, to handle when res.statusCode is an error
if (!err.status && !err.statusCode && res.statusCode >= 400)
err.statusCode = res.statusCode;
var data = buildResponseData(err, options);
debug('Response status %s data %j', data.statusCode, data);
res.setHeader('X-Content-Type-Options', 'nosniff');
res.statusCode = data.statusCode;
var sendResponse = negotiateContentProducer(req, warn, options);
sendResponse(res, data);
function warn(msg) {
res.header('X-Warning', msg);
debug(msg);
}
writeErrorToResponse(err, req, res, options);
};
};
/**
* Writes thrown error to response
*
* @param {Error} err
* @param {Express.Request} req
* @param {Express.Response} res
* @param {Object} options
*/
function writeErrorToResponse(err, req, res, options) {
debug('Handling %s', err.stack || err);
options = options || {};
if (res._header) {
debug('Response was already sent, closing the underlying connection');
return req.socket.destroy();
}
// this will alter the err object, to handle when res.statusCode is an error
if (!err.status && !err.statusCode && res.statusCode >= 400)
err.statusCode = res.statusCode;
var data = buildResponseData(err, options);
debug('Response status %s data %j', data.statusCode, data);
res.setHeader('X-Content-Type-Options', 'nosniff');
res.statusCode = data.statusCode;
var sendResponse = negotiateContentProducer(req, warn, options);
sendResponse(res, data);
function warn(msg) {
res.header('X-Warning', msg);
debug(msg);
}
};
exports = module.exports = createStrongErrorHandler;
exports.writeErrorToResponse = writeErrorToResponse;

View File

@ -17,6 +17,7 @@
"posttest": "npm run lint"
},
"dependencies": {
"@types/express": "^4.16.0",
"accepts": "^1.3.3",
"debug": "^3.1.0",
"ejs": "^2.6.1",

View File

@ -78,7 +78,8 @@ describe('strong-error-handler', function() {
request.get('/').expect(
507,
{error: {statusCode: 507, message: 'Insufficient Storage'}},
done);
done
);
});
});
@ -145,7 +146,8 @@ describe('strong-error-handler', function() {
it('handles array argument', function(done) {
givenErrorHandlerForError(
[new TypeError('ERR1'), new Error('ERR2')],
{log: true});
{log: true}
);
request.get('/api').end(function(err) {
if (err) return done(err);
@ -565,8 +567,7 @@ describe('strong-error-handler', function() {
);
done();
});
}
);
});
it('HTML-escapes all 5xx response properties in development mode',
function(done) {
@ -582,8 +583,7 @@ describe('strong-error-handler', function() {
/500(.*?)a test error message&lt;img onerror=alert\(1\) src=a&gt;/,
done
);
}
);
});
it('contains subset of properties when status=4xx', function(done) {
var error = new ErrorWithProps({
@ -750,8 +750,7 @@ describe('strong-error-handler', function() {
request.get('/')
.set('Accept', 'text/html')
.expect('Content-Type', /^application\/json/, done);
}
);
});
it('chooses resolved type when negotiateContentType=false + not-supported',
function(done) {
@ -762,8 +761,7 @@ describe('strong-error-handler', function() {
request.get('/')
.set('Accept', 'text/html')
.expect('Content-Type', /^text\/html/, done);
}
);
});
it('chooses default type when negotiateContentType=false + not-supported ',
function(done) {
@ -773,8 +771,7 @@ describe('strong-error-handler', function() {
});
request.get('/')
.expect('Content-Type', /^application\/json/, done);
}
);
});
it('honors order of accepted content-types of text/html', function(done) {
givenErrorHandlerForError(new Error('Some error'), {