From 7d2f0751f68127d3b6d05970326fe615d259d2e6 Mon Sep 17 00:00:00 2001 From: Kevin Delisle Date: Tue, 30 May 2017 14:18:40 -0400 Subject: [PATCH] Add http status code translations for errors Errors will now have their status codes set based on the error message returned by the MySQL driver. --- lib/mysql.js | 4 ++++ lib/set-http-code.js | 45 ++++++++++++++++++++++++++++++++++++++ test/set-http-code.test.js | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 lib/set-http-code.js create mode 100644 test/set-http-code.test.js diff --git a/lib/mysql.js b/lib/mysql.js index 46f8ba7..7ec1f27 100644 --- a/lib/mysql.js +++ b/lib/mysql.js @@ -16,6 +16,7 @@ var ParameterizedSQL = SqlConnector.ParameterizedSQL; var EnumFactory = require('./enumFactory').EnumFactory; var debug = require('debug')('loopback:connector:mysql'); +var setHttpCode = require('./set-http-code'); /** * @module loopback-connector-mysql @@ -186,6 +187,9 @@ MySQL.prototype.executeSQL = function(sql, params, options, callback) { if (!transaction) { connection.release(); } + if (err) { + err = setHttpCode(err); + } callback && callback(err, result); } diff --git a/lib/set-http-code.js b/lib/set-http-code.js new file mode 100644 index 0000000..1dfdce9 --- /dev/null +++ b/lib/set-http-code.js @@ -0,0 +1,45 @@ +// Copyright IBM Corp. 2012,2017. All Rights Reserved. +// Node module: loopback-connector-mysql +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +var _ = require('lodash'); + +var codes = { + '404': [ + 'ER_DB_DROP_EXISTS', + 'ER_BAD_TABLE_ERROR', + ], + '422': [ + 'ER_DUP_ENTRY', + 'ER_CANT_CREATE_DB', + 'ER_DB_CREATE_EXISTS', + 'ER_TABLE_EXISTS_ERROR', + ], +}; + +/*! + * Translate MySQL error codes into HTTP Errors. + * If an error would be better represented by a code that isn't 500, + * add your SQL error to the correct HTTP code array above! + */ +module.exports = function(err) { + if (!err) { + return; + } else if (!(err instanceof Error)) { + err = new Error(err); // Sucks that we weren't given an error object... + } + // Find error prefix + var msg = err.message; + var sqlError = msg.substring(0, msg.indexOf(':')); + + for (var code in codes) { + if (_.includes(codes[code], sqlError)) { + err.statusCode = code; + } + } + if (!err.statusCode) err.statusCode = 500; + return err; +}; diff --git a/test/set-http-code.test.js b/test/set-http-code.test.js new file mode 100644 index 0000000..71eeb86 --- /dev/null +++ b/test/set-http-code.test.js @@ -0,0 +1,43 @@ +// Copyright IBM Corp. 2012,2017. All Rights Reserved. +// Node module: loopback-connector-mysql +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +var setHttpCode = require('../lib/set-http-code'); +var should = require('./init.js'); + +describe('setHttpCode', function() { + describe('should set statusCode', function() { + testErrorCode('404 on db not found', 'ER_DB_DROP_EXISTS: Nope', 404); + testErrorCode('404 on table not found', 'ER_BAD_TABLE_ERROR: Nope', 404); + + testErrorCode('422 on duplicates', 'ER_DUP_ENTRY: Duplicate entry', 422); + testErrorCode('422 on cannot create db', 'ER_CANT_CREATE_DB: Oops', 422); + testErrorCode('422 on db already exists', 'ER_DB_CREATE_EXISTS: Oops', 422); + testErrorCode('422 on db not found', 'ER_TABLE_EXISTS_ERROR: Nope', 422); + + testErrorCode('500 on unknown errors', 'FATAL: Sadness happened', 500); + + function testErrorCode(name, msg, expected) { + it(name, function() { + var err = new Error(msg); + err = setHttpCode(err); + should.exist(err.statusCode); + should.equal(err.statusCode, expected); + }); + } + }); + it('should do nothing without error', function() { + should.doesNotThrow(setHttpCode); + }); + + it('should convert strings to errors', function() { + var err = 'REALLY_BAD: Something truly awful occurred.'; + err = setHttpCode(err); + should.exist(err.statusCode); + should(err instanceof Error); + should.equal(err.statusCode, 500); + }); +});