I am currently trying to handle exceptions and errors in a NodeJS app which will be used for critical information. I need a clean error management !
I've been wondering if there is something similar to Java Exceptions encapsulation.
I'm explaning.
In Java you can do something like that :
try {
// something that throws Exception
} catch (Throwable t) {
throw new Exception("My message", t);
}
That allows you to decide when to log your exception and you get the whole stack trace and call path !
I would like to know if there is a way to do the same in NodeJS because logging at every step seems not to be the right way of doing things.
Thank you.
You should look at this module :
https://www.npmjs.com/package/verror
Joyent quote it on his error management best pratices : https://www.joyent.com/developers/node/design/errors
At Joyent, we use the verror module to wrap errors since it's
syntactically concise. As of this writing, it doesn't quite do all of
this yet, but it will be extended to do so.
It allow you to get details on error message. And tracking the step of the error.
And also hide details to the client with wrapped error : WError() who returns only the last error message.
I answer my own question to explain what i finaly did to have the wanted encapsulation.
I used https://www.npmjs.com/package/verror as Sachacr suggested.
Then I extended it that way :
my_error.js :
var VError = require('verror');
var _ = require('lodash');
function MyError() {
var args = [];
var httpErrorCode;
var cause;
if (arguments.length > 0) {
var lastArgumentIndex = [arguments.length];
cause = manageCause(lastArgumentIndex, arguments);
httpErrorCode = manageHttpCode(lastArgumentIndex, arguments);
for (var i = 0; i < lastArgumentIndex; i++) {
args[i] = arguments[i];
}
}
this.__proto__.__proto__.constructor.apply(this, args);
if (cause) {
if (this.stack) {
this.stack += '\n' + cause.stack;
} else {
this.stack = cause.stack;
}
}
this.httpErrorCode = httpErrorCode;
}
MyError.prototype.__proto__ = VError.prototype;
function manageCause(lastArgumentIndex, arguments) {
if (lastArgumentIndex[0] > 0
&& arguments[lastArgumentIndex[0] - 1] instanceof Error) {
lastArgumentIndex[0]--;
return arguments[lastArgumentIndex[0]];
}
}
function manageHttpCode(lastArgumentIndex, arguments) {
if (lastArgumentIndex[0] > 0
&& _.isNumber(arguments[lastArgumentIndex[0] - 1])) {
lastArgumentIndex[0]--;
return arguments[lastArgumentIndex[0]];
}
}
module.exports = MyError;
It allows me to use it easily in my code :
var MyError = require('./my_error.js');
function withErrors() {
try {
// something with errors
} catch (err) {
// This is the same pattern as VError
return new MyError("My message", err, 401);
}
}
function somethingToDo(req, res) {
var result = withErrors();
if (result instanceof MyError) {
logger.warn(result);
res.status(result.httpErrorCode).send(result.message).end();
return
}
}
That way, i hace a nice stack trace with call path and every line involved in error/exception.
Hope it will help people, cause i searched a looooong time :)
EDIT : I modified my MyError class to add HTTP Error codes and clean arguments management.
You should be able to do something like:
funtion exception(message, error) {
this.message = message;
this.stacktrace = error.stack;
}
try {
if(someData == false)
throw new exception("something went wrong!", new Error());
}
catch(ex) {
console.log(ex.message);
console.log(ex.stacktrace);
}
You can then throw your own custom exception instance containing whatever debugging info you need.
EDIT: added stack trace to exception object
Related
I have NodeJS program.
In one class, I have various utility methods. One function, safeGithubPush, calls safeString, another func in the same class
module.exports = {
safeString(stringToCheck) {
console.log(validator.isAscii(stringToCheck), validator.matches(stringToCheck, /^((\w)*[-.]?(\w)*)*$/))
return (
validator.isAscii(stringToCheck) &&
validator.matches(stringToCheck, /^((\w)*[-.]?(\w)*)*$/)
);
},
safeGithubPush(currentJob) {
if (
!currentJob ||
!currentJob.payload ||
!currentJob.payload.repoName ||
!currentJob.payload.repoOwner ||
!currentJob.payload.branchName
) {
this.logIn(
currentJob,
`${' (sanitize)'.padEnd(15)}failed due to insufficient job definition`
);
throw invalidJobDef;
}
if (
this.safeString(currentJob.payload.repoName) &&
this.safeString(currentJob.payload.repoOwner) &&
this.safeString(currentJob.payload.branchName)
) {
return true;
}
throw invalidJobDef;
},
}
While this.logIn(), another func in the utility class, works just fine, I get the error for safeString:
Error caught by first catch: TypeError: this.safeString is not a function
I followed a solution offer by another SO post:
safeString: function(stringToCheck){
...
}
safeGithubPush(currentJob) {
...
if (
this.safeString(currentJob.payload.repoName) &&
this.safeString(currentJob.payload.repoOwner) &&
this.safeString(currentJob.payload.branchName)
) {
return true;
}
}
But this also gets a, TypeError: this.safeString is not a function.
I'm not using arrow functions, which is the explanation for this error on a different SO post
I don't think the reason is determinable with the code you are currently presenting. It likely has something to do with how you are calling safeGithubPush. If you do something that would change the this binding the this.safeString is going to fail.
const foo = {
fizz() {
console.log("fizz");
},
buzz() {
this.fizz();
}
};
// "this" is correct
foo.buzz();
// "this" has no fizz to call
const myFizz = foo.buzz;
myFizz();
Considering you are attaching these to module.exports I am going to guess that you pull these functions off in a require call and then try to use them bare which makes the problem obvious after looking at my example above:
// Ignore these 2 lines, they let this look like node
const module = {};
const require = () => module.exports;
// Ignore above 2 lines, they let this look like node
// Your module "some.js"
module.exports = {
safeString(str) {
return true;
},
safeGithubPush(currentJob) {
if (!this.safeString("some")) {
throw new Error("Not safe");
}
return true;
}
};
try {
// Some consumer module that doesn't work
const {safeGithubPush} = require("./some.js");
const isItSafe = safeGithubPush();
console.log(`Safe? ${isItSafe}`);
} catch (err) {
console.error("Didn't bind right \"this\"");
}
try {
// Some consumer module that DOES work
const someModule = require("./some.js");
const isItSafe = someModule.safeGithubPush();
console.log(`Safe? ${isItSafe}`);
} catch (err) {
console.error(err);
}
I would restructure this code. You say these are utility functions which makes me think you don't really want to have to structure them with this in mind.
Instead of attaching them all to module.exports at their definition, define them outside and directly reference the functions you want to use, then attach them to exports so other modules can use the functions:
function safeString(stringToCheck) {
return true;
}
function safeGithubPush(currentJob) {
if (!safeString("some")) {
throw new Error("Not safe");
}
return true;
}
module.exports = {
safeString,
safeGithubPush
};
I am developing a small page/router component on a website using Angular 7 and its CLI. At one point I need to check if the user has allowed flash, I do this by doing so:
checkFlash() {
var hasFlash = false;
try {
hasFlash = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"));
} catch (exception) {
hasFlash = "undefined" != typeof navigator.mimeTypes["application/x-shockwave-flash"];
}
return hasFlash;
}
I found this off here, and it works great, but now as I am cleaning up my application I am noticing that Angular doesn't seem to like this, in fact, it says that ActiveXObject isn't defined, yet it still works.
Super confused...
I tried linking an actual flash object like so $('embed[type="application/x-shockwave-flash"]') or $('embed[type="application/x-shockwave-flash"]')[0] but had no luck, it always returned true.
I tried installing extra npm(s) including ones like activex-support and activex-data-support as well as their #types cousins. After setting them up I found out that they did nothing to help my case.
Here are the exact errors the CLI & VScode-Intellisense gave me:
VScode:
[ts] 'ActiveXObject' only refers to a type, but is being used as a value here. [2693]
any
CLI:
ERROR in src/app/games/games.component.ts(51,30): error TS2304: Cannot find name 'ActiveXObject'.
It doesn't throw this error when ran inside plain JS, but I've looked around and can't seem to figure out how to run pure JS inside Angular 2 (7). Also looked here with no luck.
Please help, completely lost here.
EDIT: Found the fix -->
The answer was here listed inside the comments (will need to make minor changes)(shown below)
change from:
checkFlash() {
var hasFlash = false;
try {
hasFlash = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"));
} catch (exception) {
hasFlash = "undefined" != typeof navigator.mimeTypes["application/x-
shockwave-flash"];
}
return hasFlash;
}
to:
function checkFlash() {
var hasFlash = false;
try {
var flash =
navigator.mimeTypes &&
navigator.mimeTypes["application/x-shockwave-flash"]
? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin
: 0;
if (flash) hasFlash = true;
} catch (e) {
if (navigator.mimeTypes["application/x-shockwave-flash"] != undefined)
hasFlash = true;
}
return hasFlash;
}
This issue with ActiveXObject can be solve as shown below:
Goto your tsconfig.json file and add the 'scripthost' library.
Then recompile your application.
"lib": [
"es2017",
"dom",
"scripthost"
]
The answer was here listed inside the comments (will need to make minor changes)(shown below)
change from:
checkFlash() {
var hasFlash = false;
try {
hasFlash = Boolean(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"));
} catch (exception) {
hasFlash = "undefined" != typeof navigator.mimeTypes["application/x-
shockwave-flash"];
}
return hasFlash;
}
to:
function checkFlash() {
var hasFlash = false;
try {
var flash =
navigator.mimeTypes &&
navigator.mimeTypes["application/x-shockwave-flash"]
? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin
: 0;
if (flash) hasFlash = true;
} catch (e) {
if (navigator.mimeTypes["application/x-shockwave-flash"] != undefined)
hasFlash = true;
}
return hasFlash;
}
I'd like to have my unit tests assert that a particular function call throws an AssertionError specifically when expected, rather than that it throws an exception at all. The assertion library (expect) supports such a thing by passing an exception constructor in, but I can't seem to find where, if anywhere, the AssertionError constructor is exported. Is it intended to be an internal class only and not exposed to us? The docs contain numerous references to it, but no links.
I have a super hacky way:
let AssertionError;
try {
const assert = require("assert");
assert.fail();
}
catch (ex) {
AssertionError = ex.constructor;
}
but I'm hoping there's a better way.
Assertion error class is defined here:
assert.AssertionError
*It can be useful while testing and AsserionError is expected result:
assert.throws( FunctionThatShouldThrow_AssertionError, assert.AssertionError )
After a research in the Nodejs github repo, I can tell you it is here:
https://github.com/nodejs/node/blob/c75f87cc4c8d3699e081d37bb5bf47a70d830fdb/lib/internal/errors.js
AssertionError is defined like this :
class AssertionError extends Error {
constructor(options) {
if (typeof options !== 'object' || options === null) {
throw new exports.TypeError('ERR_INVALID_ARG_TYPE', 'options', 'object');
}
var { actual, expected, message, operator, stackStartFunction } = options;
if (message) {
super(message);
} else {
if (actual && actual.stack && actual instanceof Error)
actual = `${actual.name}: ${actual.message}`;
if (expected && expected.stack && expected instanceof Error)
expected = `${expected.name}: ${expected.message}`;
if (util === null) util = require('util');
super(`${util.inspect(actual).slice(0, 128)} ` +
`${operator} ${util.inspect(expected).slice(0, 128)}`);
}
this.generatedMessage = !message;
this.name = 'AssertionError [ERR_ASSERTION]';
this.code = 'ERR_ASSERTION';
this.actual = actual;
this.expected = expected;
this.operator = operator;
Error.captureStackTrace(this, stackStartFunction);
}
}
If I were you, I would not redefined AssertionError, that is very, very hacky. I think your best bet is to extend that class to MyAssertionError or to create a twin than extends error.
Hope that helps!
I have a library that connects to a remote API:
class Client(access_token) {
void put(key, value, callback);
void get(key, callback);
}
I want to set up a Node.js REPL to make it easy to try things out:
var repl = require('repl');
var r = repl.start('> ');
r.context.client = new Client(...);
The problem is that an asynchronous API is not convenient for a REPL. I'd prefer a synchronous one that yields the result via the return value and signals an error with an exception. Something like:
class ReplClient(access_token) {
void put(key, value); // throws NetworkError
string get(key); // throws NetworkError
}
Is there a way to implement ReplClient using Client? I'd prefer to avoid any dependencies other than the standard Node.js packages.
You can synchronously wait for stuff with the magic of wait-for-stuff.
Based on your example specification:
const wait = require('wait-for-stuff')
class ReplClient {
constructor(access_token) {
this.client = new Client(access_token)
}
put(key, value) {
return checkErr(wait.for.promise(this.client.put(key, value)))
}
get(key) {
return checkErr(wait.for.promise(this.client.get(key)))
}
}
const checkErr = (maybeErr) => {
if (maybeErr instanceof Error) {
throw maybeErr
} else {
return maybeErr
}
}
I'm using chrome.storage in an extension and would like to avoid triggering runtime errors due to exceeding one of the documented throttles for either the sync or local stores. (things like QUOTA_BYTES, QUOTA_BYTES_PER_ITEM)
My first choice would be to intercept these errors prior to a runtime error being generated; alternatively I could track usage on the extension side and try to avoid triggering them.
This feels like an issue that someone must have addressed, but I can't seem to find any solutions - any suggestions appreciated.
Here's a sample of the solution I'm going with (using Angular, so there are promises in here), although having to regex the chrome.runtime.lastError value is pretty ugly IMO:
var service = {
error: function(lastError) {
if((lastError) && (lastError.message)) {
var errorString = lastError.message;
if(/QUOTA_BYTES/.test(errorString)) {
return true;
} else if(/QUOTA_BYTES_PER_ITEM/.test(errorString)) {
return true;
} else if(/MAX_ITEMS/.test(errorString)) {
return true;
} else if(/MAX_WRITE_OPERATIONS_PER_HOUR/.test(errorString)) {
return true;
} else if(/MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE/.test(errorString)) {
return true;
}
return false;
} else {
return false;
}
},
write: function(key, value) {
var deferred = $q.defer();
var data = {};
data[key] = value;
chrome.storage.sync.set(data, function() {
if(service.error(chrome.runtime.lastError)) {
deferred.reject('Write operation failed: '
+ chrome.runtime.lastError.message);
} else {
deferred.resolve();
}
});
return deferred.promise;
}
};
return service;