From 2778c864ff6883f3fc35ebf83031e3c52b874739 Mon Sep 17 00:00:00 2001 From: Guilherme Hermeto Date: Wed, 15 May 2019 02:02:46 -0700 Subject: [PATCH] feat: adds support to http problems - RFC7807 adds supports to handle error objects comforming with the http problem details spec (RFC7807). the spec defines a `status` field instead of `statusCode` and a `application/problem+json` content type. --- .gitignore | 1 + lib/formatters/index.js | 3 ++- lib/response.js | 9 +++++++-- lib/server.js | 2 +- test/response.test.js | 35 +++++++++++++++++++++++++++++++++++ test/server.test.js | 3 ++- 6 files changed, 48 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 883db1f28..1a8787318 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ deps/javascriptlint deps/jsstyle package-lock.json benchmark/results +.idea diff --git a/lib/formatters/index.js b/lib/formatters/index.js index 467cafb5b..9532bd330 100644 --- a/lib/formatters/index.js +++ b/lib/formatters/index.js @@ -18,5 +18,6 @@ module.exports = { 'application/javascript; q=0.1': require('./jsonp'), 'application/json; q=0.4': require('./json'), 'text/plain; q=0.3': require('./text'), - 'application/octet-stream; q=0.2': require('./binary') + 'application/octet-stream; q=0.2': require('./binary'), + 'application/problem+json; q=0.5': require('./json') }; diff --git a/lib/response.js b/lib/response.js index ebf427d42..e04318cf9 100644 --- a/lib/response.js +++ b/lib/response.js @@ -389,7 +389,7 @@ function patch(Response) { // If the body is an error object and we were not given a status code, // try to derive it from the error object, otherwise default to 500 if (!code && body instanceof Error) { - code = body.statusCode || 500; + code = body.statusCode || body.status || 500; } // Set sane defaults for optional arguments if they were not provided @@ -441,7 +441,12 @@ function patch(Response) { // Set Content-Type to application/json when // res.send is called with an Object instead of calling res.json if (!type && typeof body === 'object' && !Buffer.isBuffer(body)) { - type = 'application/json'; + // if Error that conforms with rfc7807 use the correct type + if (body instanceof Error && body.status && !body.statusCode) { + type = 'application/problem+json'; + } else { + type = 'application/json'; + } } // Derive type if not provided by the user diff --git a/lib/server.js b/lib/server.js index d3da14442..05553ff34 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1435,7 +1435,7 @@ Server.prototype._routeErrorResponse = function _routeErrorResponse( } // only automatically send errors that are known (e.g., restify-errors) - if (err instanceof Error && _.isNumber(err.statusCode)) { + if (err instanceof Error && _.isNumber(err.statusCode || err.status)) { res.send(err); return; } diff --git a/test/response.test.js b/test/response.test.js index a3866af21..4fb0776f9 100644 --- a/test/response.test.js +++ b/test/response.test.js @@ -680,3 +680,38 @@ test('GH-1607: should send numbers with explicit status code', function(t) { }); }); }); + +test('should handle errors with a status property', function(t) { + var notFound = new Error('not found'); + notFound.status = 404; + notFound.title = 'Not Found'; + + SERVER.get('/17', function handle(req, res, next) { + return next(notFound); + }); + + CLIENT.get(join(LOCALHOST, '/17'), function(err, _, res, body) { + t.equal(res.statusCode, 404); + t.equal(res.headers['content-type'], 'application/problem+json'); + t.equal(body.title, notFound.title); + t.end(); + }); +}); + +test('should prefer error statusCode property over status', function(t) { + var notFound = new Error('not found'); + notFound.statusCode = 404; + notFound.status = 500; + notFound.title = 'Not Found'; + + SERVER.get('/18', function handle(req, res, next) { + return next(notFound); + }); + + CLIENT.get(join(LOCALHOST, '/18'), function(err, _, res, body) { + t.equal(res.statusCode, 404); + t.equal(res.headers['content-type'], 'application/json'); + t.equal(body.title, notFound.title); + t.end(); + }); +}); diff --git a/test/server.test.js b/test/server.test.js index 4e7e3382d..319a22071 100644 --- a/test/server.test.js +++ b/test/server.test.js @@ -2333,7 +2333,8 @@ test('should show debug information', function(t) { 'application/javascript', 'application/json', 'text/plain', - 'application/octet-stream' + 'application/octet-stream', + 'application/problem+json' ]); t.equal(debugInfo.server.address, '127.0.0.1'); t.equal(typeof debugInfo.server.port, 'number');