diff --git a/README.md b/README.md index 8be6ffe..e6c75e9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ In production mode, `strong-error-handler` omits details from error responses to - For 5xx errors, the output contains only the status code and the status name from the HTTP specification. - For 4xx errors, the output contains the full error message (`error.message`) and the contents of the `details` property (`error.details`) that `ValidationError` typically uses to provide machine-readable details - about validation problems. + about validation problems. It also includes `error.code` to allow a machine-readable error code to be passed + through which could be used, for example, for translation. In debug mode, `strong-error-handler` returns full error stack traces and internal details of any error objects to the client in the HTTP responses. @@ -204,13 +205,13 @@ For more information, see ## Example -Error generated when `debug: false` : +5xx error generated when `debug: false` : ``` { error: { statusCode: 500, message: 'Internal Server Error' } } ``` -Error generated when `debug: true` : +The same error generated when `debug: true` : ``` { error: @@ -230,3 +231,14 @@ Error generated when `debug: true` : at tryOnImmediate (timers.js:543:15) at processImmediate [as _immediateCallback] (timers.js:523:5)' }} ``` + +4xx error generated when `debug: false` : + +``` +{ error: + { statusCode: 422, + name: 'Unprocessable Entity', + message: 'Missing required fields', + code: 'MISSING_REQUIRED_FIELDS' }} +``` + diff --git a/lib/data-builder.js b/lib/data-builder.js index 40fbfe9..5505d31 100644 --- a/lib/data-builder.js +++ b/lib/data-builder.js @@ -77,6 +77,7 @@ function fillDebugData(data, err) { function fillBadRequestError(data, err) { data.name = err.name; data.message = err.message; + data.code = err.code; data.details = err.details; } diff --git a/test/handler.test.js b/test/handler.test.js index 86b6a81..1e533ed 100644 --- a/test/handler.test.js +++ b/test/handler.test.js @@ -193,6 +193,7 @@ describe('strong-error-handler', function() { it('contains all error properties when debug=true', function(done) { var error = new ErrorWithProps({ message: 'a test error message', + code: 'MACHINE_READABLE_CODE', details: 'some details', extra: 'sensitive data', }); @@ -205,6 +206,7 @@ describe('strong-error-handler', function() { statusCode: 500, message: 'a test error message', name: 'ErrorWithProps', + code: 'MACHINE_READABLE_CODE', details: 'some details', extra: 'sensitive data', stack: error.stack, @@ -215,6 +217,52 @@ describe('strong-error-handler', function() { }); }); + it('includes code property for 4xx status codes when debug=false', + function(done) { + var error = new ErrorWithProps({ + statusCode: 400, + message: 'error with code', + name: 'ErrorWithCode', + code: 'MACHINE_READABLE_CODE', + }); + givenErrorHandlerForError(error, {debug: false}); + + requestJson().end(function(err, res) { + if (err) return done(err); + + var expectedData = { + statusCode: 400, + message: 'error with code', + name: 'ErrorWithCode', + code: 'MACHINE_READABLE_CODE', + }; + expect(res.body).to.have.property('error'); + expect(res.body.error).to.eql(expectedData); + done(); + }); + }); + + it('excludes code property for 5xx status codes when debug=false', + function(done) { + var error = new ErrorWithProps({ + statusCode: 500, + code: 'MACHINE_READABLE_CODE', + }); + givenErrorHandlerForError(error, {debug: false}); + + requestJson().end(function(err, res) { + if (err) return done(err); + + var expectedData = { + statusCode: 500, + message: 'Internal Server Error', + }; + expect(res.body).to.have.property('error'); + expect(res.body.error).to.eql(expectedData); + done(); + }); + }); + it('contains non-enumerable Error properties when debug=true', function(done) { var error = new Error('a test error message');