Allow safeFields to work with arrays

Co-authored-by: Miroslav Bajtos <mbajtoss@gmail.com>
This commit is contained in:
shimks 2018-05-31 13:13:14 -04:00
parent a431cf54fa
commit 7828534804
2 changed files with 86 additions and 41 deletions

View File

@ -8,16 +8,18 @@
var cloneAllProperties = require('../lib/clone.js'); var cloneAllProperties = require('../lib/clone.js');
var httpStatus = require('http-status'); var httpStatus = require('http-status');
module.exports = function buildResponseData(err, options) { module.exports = buildResponseData;
function buildResponseData(err, options) {
// Debugging mode is disabled by default. When turned on (in dev), // Debugging mode is disabled by default. When turned on (in dev),
// all error properties (including) stack traces are sent in the response // all error properties (including) stack traces are sent in the response
var isDebugMode = options.debug; const isDebugMode = options.debug;
if (Array.isArray(err) && isDebugMode) { if (Array.isArray(err)) {
err = serializeArrayOfErrors(err); return serializeArrayOfErrors(err, options);
} }
var data = Object.create(null); const data = Object.create(null);
fillStatusCode(data, err); fillStatusCode(data, err);
if (typeof err !== 'object') { if (typeof err !== 'object') {
@ -29,35 +31,25 @@ module.exports = function buildResponseData(err, options) {
if (isDebugMode) { if (isDebugMode) {
fillDebugData(data, err); fillDebugData(data, err);
} else if (data.statusCode >= 400 && data.statusCode <= 499) { return data;
}
if (data.statusCode >= 400 && data.statusCode <= 499) {
fillBadRequestError(data, err); fillBadRequestError(data, err);
} else { } else {
fillInternalError(data, err); fillInternalError(data, err);
} }
var safeFields = options.safeFields || []; const safeFields = options.safeFields || [];
fillSafeFields(data, err, safeFields); fillSafeFields(data, err, safeFields);
return data; return data;
}; };
function serializeArrayOfErrors(errors) { function serializeArrayOfErrors(errors, options) {
var details = []; const details = errors.map(e => buildResponseData(e, options));
for (var ix in errors) {
var err = errors[ix];
if (typeof err !== 'object') {
details.push('' + err);
continue;
}
var data = {};
cloneAllProperties(data, err);
delete data.statusCode;
details.push(data);
}
return { return {
name: 'ArrayOfErrors', statusCode: 500,
message: 'Failed with multiple errors, ' + message: 'Failed with multiple errors, ' +
'see `details` for more information.', 'see `details` for more information.',
details: details, details: details,

View File

@ -397,48 +397,101 @@ describe('strong-error-handler', function() {
requestJson().expect(500).end(function(err, res) { requestJson().expect(500).end(function(err, res) {
if (err) return done(err); if (err) return done(err);
expect(res.body).to.eql({ const data = res.body.error;
error: { expect(data).to.have.property('message').that.match(/multiple errors/);
statusCode: 500, expect(data).to.have.property('details').eql([
message: 'Internal Server Error', {statusCode: 500, message: 'Internal Server Error'},
}, {statusCode: 500, message: 'Internal Server Error'},
}); {statusCode: 500, message: 'Internal Server Error'},
]);
done(); done();
}); });
}); });
it('returns all array items when debug=true', function(done) { it('returns all array items when debug=true', function(done) {
var testError = new ErrorWithProps({ const testError = new ErrorWithProps({
message: 'expected test error', message: 'expected test error',
statusCode: 400, statusCode: 400,
}); });
var anotherError = new ErrorWithProps({ const anotherError = new ErrorWithProps({
message: 'another expected error', message: 'another expected error',
statusCode: 500, statusCode: 500,
}); });
var errors = [testError, anotherError, 'ERR STRING']; const errors = [testError, anotherError, 'ERR STRING'];
givenErrorHandlerForError(errors, {debug: true}); givenErrorHandlerForError(errors, {debug: true});
requestJson().expect(500).end(function(err, res) { requestJson().expect(500).end(function(err, res) {
if (err) return done(err); if (err) return done(err);
var data = res.body.error; const data = res.body.error;
expect(data).to.have.property('message').that.match(/multiple errors/); expect(data).to.have.property('message').that.match(/multiple errors/);
var expectTestError = getExpectedErrorData(testError);
delete expectTestError.statusCode;
var expectAnotherError = getExpectedErrorData(anotherError);
delete expectAnotherError.statusCode;
var expectedDetails = [ const expectedDetails = [
expectTestError, getExpectedErrorData(testError),
expectAnotherError, getExpectedErrorData(anotherError),
'ERR STRING', {message: 'ERR STRING', statusCode: 500},
]; ];
expect(data).to.have.property('details').to.eql(expectedDetails); expect(data).to.have.property('details').to.eql(expectedDetails);
done(); done();
}); });
}); });
it('includes safeFields of array items when debug=false', (done) => {
const internalError = new ErrorWithProps({
message: 'a test error message',
code: 'MACHINE_READABLE_CODE',
details: 'some details',
extra: 'sensitive data',
});
const validationError = new ErrorWithProps({
name: 'ValidationError',
message: 'The model instance is not valid.',
statusCode: 422,
code: 'VALIDATION_ERROR',
details: 'some details',
extra: 'sensitive data',
});
const errors = [internalError, validationError, 'ERR STRING'];
givenErrorHandlerForError(errors, {
debug: false,
safeFields: ['code'],
});
requestJson().end(function(err, res) {
if (err) return done(err);
const data = res.body.error;
const expectedInternalError = {
statusCode: 500,
message: 'Internal Server Error',
code: 'MACHINE_READABLE_CODE',
// notice the property "extra" is not included
};
const expectedValidationError = {
statusCode: 422,
message: 'The model instance is not valid.',
name: 'ValidationError',
code: 'VALIDATION_ERROR',
details: 'some details',
// notice the property "extra" is not included
};
const expectedErrorFromString = {
message: 'Internal Server Error',
statusCode: 500,
};
const expectedDetails = [
expectedInternalError,
expectedValidationError,
expectedErrorFromString,
];
expect(data).to.have.property('message').that.match(/multiple errors/);
expect(data).to.have.property('details').to.eql(expectedDetails);
done();
});
});
it('handles non-Error argument as 500 when debug=false', function(done) { it('handles non-Error argument as 500 when debug=false', function(done) {
givenErrorHandlerForError('Error Message', {debug: false}); givenErrorHandlerForError('Error Message', {debug: false});
requestJson().expect(500).end(function(err, res) { requestJson().expect(500).end(function(err, res) {