Add type definition and writeErrorToResponse
This commit is contained in:
parent
8b35494da0
commit
80ebf30cfa
23
README.md
23
README.md
|
@ -46,6 +46,29 @@ app.use(errorHandler({
|
||||||
app.listen(3000);
|
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`:
|
In LoopBack applications, add the following entry to `server/middleware.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ function noop() {
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
exports = module.exports = function createStrongErrorHandler(options) {
|
function createStrongErrorHandler(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
debug('Initializing with options %j', options);
|
debug('Initializing with options %j', options);
|
||||||
|
@ -32,31 +32,47 @@ exports = module.exports = function createStrongErrorHandler(options) {
|
||||||
var logError = options.log !== false ? logToConsole : noop;
|
var logError = options.log !== false ? logToConsole : noop;
|
||||||
|
|
||||||
return function strongErrorHandler(err, req, res, next) {
|
return function strongErrorHandler(err, req, res, next) {
|
||||||
debug('Handling %s', err.stack || err);
|
|
||||||
|
|
||||||
logError(req, err);
|
logError(req, err);
|
||||||
|
writeErrorToResponse(err, req, res, 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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"posttest": "npm run lint"
|
"posttest": "npm run lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/express": "^4.16.0",
|
||||||
"accepts": "^1.3.3",
|
"accepts": "^1.3.3",
|
||||||
"debug": "^3.1.0",
|
"debug": "^3.1.0",
|
||||||
"ejs": "^2.6.1",
|
"ejs": "^2.6.1",
|
||||||
|
|
|
@ -78,7 +78,8 @@ describe('strong-error-handler', function() {
|
||||||
request.get('/').expect(
|
request.get('/').expect(
|
||||||
507,
|
507,
|
||||||
{error: {statusCode: 507, message: 'Insufficient Storage'}},
|
{error: {statusCode: 507, message: 'Insufficient Storage'}},
|
||||||
done);
|
done
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -145,7 +146,8 @@ describe('strong-error-handler', function() {
|
||||||
it('handles array argument', function(done) {
|
it('handles array argument', function(done) {
|
||||||
givenErrorHandlerForError(
|
givenErrorHandlerForError(
|
||||||
[new TypeError('ERR1'), new Error('ERR2')],
|
[new TypeError('ERR1'), new Error('ERR2')],
|
||||||
{log: true});
|
{log: true}
|
||||||
|
);
|
||||||
|
|
||||||
request.get('/api').end(function(err) {
|
request.get('/api').end(function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
@ -565,8 +567,7 @@ describe('strong-error-handler', function() {
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
it('HTML-escapes all 5xx response properties in development mode',
|
it('HTML-escapes all 5xx response properties in development mode',
|
||||||
function(done) {
|
function(done) {
|
||||||
|
@ -582,8 +583,7 @@ describe('strong-error-handler', function() {
|
||||||
/500(.*?)a test error message<img onerror=alert\(1\) src=a>/,
|
/500(.*?)a test error message<img onerror=alert\(1\) src=a>/,
|
||||||
done
|
done
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
it('contains subset of properties when status=4xx', function(done) {
|
it('contains subset of properties when status=4xx', function(done) {
|
||||||
var error = new ErrorWithProps({
|
var error = new ErrorWithProps({
|
||||||
|
@ -750,8 +750,7 @@ describe('strong-error-handler', function() {
|
||||||
request.get('/')
|
request.get('/')
|
||||||
.set('Accept', 'text/html')
|
.set('Accept', 'text/html')
|
||||||
.expect('Content-Type', /^application\/json/, done);
|
.expect('Content-Type', /^application\/json/, done);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
it('chooses resolved type when negotiateContentType=false + not-supported',
|
it('chooses resolved type when negotiateContentType=false + not-supported',
|
||||||
function(done) {
|
function(done) {
|
||||||
|
@ -762,8 +761,7 @@ describe('strong-error-handler', function() {
|
||||||
request.get('/')
|
request.get('/')
|
||||||
.set('Accept', 'text/html')
|
.set('Accept', 'text/html')
|
||||||
.expect('Content-Type', /^text\/html/, done);
|
.expect('Content-Type', /^text\/html/, done);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
it('chooses default type when negotiateContentType=false + not-supported ',
|
it('chooses default type when negotiateContentType=false + not-supported ',
|
||||||
function(done) {
|
function(done) {
|
||||||
|
@ -773,8 +771,7 @@ describe('strong-error-handler', function() {
|
||||||
});
|
});
|
||||||
request.get('/')
|
request.get('/')
|
||||||
.expect('Content-Type', /^application\/json/, done);
|
.expect('Content-Type', /^application\/json/, done);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
it('honors order of accepted content-types of text/html', function(done) {
|
it('honors order of accepted content-types of text/html', function(done) {
|
||||||
givenErrorHandlerForError(new Error('Some error'), {
|
givenErrorHandlerForError(new Error('Some error'), {
|
||||||
|
|
Loading…
Reference in New Issue