Error handle in Meteor in calling server side method - javascript

I call a method for deleting family from server/publicationMehods like this:
deletedFamily(family) {
if (Meteor.user().roles[0] == "admin") {
var myUsers = Meteor.users.find({"profile.family_id": family._id}).fetch();
for (var i = 0; i < myUsers.length; i++) {
UsersDeleted.insert(myUsers[i]);
Meteor.users.remove(myUsers[i]);
}
var myGuests= Guests.find({"profile.family_id": family._id}).fetch();
for (var i = 0; i < myGuests.length; i++) {
GuestsDeleted.insert(myGuests[i]);
Guests.remove(myGuests[i]);
}
FamiliesDeleted.insert(family);
Families.remove(family);
}
}
I want to handle exception and catch it if any errors happend and in frond-end show the result. I know there is not any transaction in Meteor. But I need to show the result to user at least.

In Meteor, if you want to return an error to a user from a Meteor method then you throw an exception, but it must be a Meteor.Error exception object in order to send it back to the client.
On the client side, when you call a Meteor method on the server, you provide a callback function that receives an error and result. If you wish to display an error to the user then whatever Meteor.Error exception object that was thrown in the method will be in the error callback argument.
Here is an example. First let's look at the meteor method throwing an exception.
Meteor.methods({
deletedFamily: function(family) {
//... your logic here...
if (somethingWentWrong) {
throw new Meteor.Error("logged-out", "The user must be logged in to delete a family.");
} else {
return // something
}
},
});
On the client, you would call the method like this and if an error was thrown it will be in the error object.
// on the client
Meteor.call("deletedFamily", function (error, result) {
// identify the error
if (error && error.error === "logged-out") {
// show a nice error message
Session.set("errorMessage", "Please log in to delete a family.");
}
//...continue on with your logic...
});
If you need to pass along an exception generated by something else (mongodb for example), then just use try/catch blocks and pass a Meteor.Error when needed. Here is an example.
Meteor.methods({
deletedFamily: function(family) {
//... your logic here...
try {
// Mongodb insert or update
} catch(e) {
if (e instanceof WriteError && e.code === '11000') {
throw new Meteor.Error("duplicate-error", "The family already exists.");
}
}
},
});

You can use throw/catch.
Read the following document:
Throw

Related

Can we reset streamwriter data for inbound integration?

Just wondering if we are able to re-write data that we was set via the setWriteString() method while responding to an inbound api call. For example, let's say the scripted rest resource code is as follows:
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var body = request.body.data;
/* do something with request data
..
..
..
then start preparing the response
*/
var writer = response.getStreamWriter();
try
{
response.setContentType('application/json');
response.setStatus(200);
writer.writeString("{\"results\":[");
var inc = new GlideRecord('incident');
inc.query();
while(inc.next()){
var obj = {};
obj.id = inc.getValue('number');
obj.sys_id = inc.getUniqueValue();
writer.writeString(global.JSON.stringify(obj));
if (inc.hasNext()) {
writer.writeString(",");
}
}
writer.writeString("]}");
}
catch (ex)
{
// let's say exception was thrown on the 3rd iteration while gliding the incident table
// oh no...an exception..so we need to write something else to the stream
// is it possible to erase/remove everything that was added to the stream up until the exception occured?
// so that the response will contain details only about the error?
// something like below:
response.setContentType('application/json');
response.setStatus(500);
writer.writeString("{\"error\":\"Something went wrong\"}"); // this isn't working btw...the stream contained both the content generated in "try" block as well as the "catch" block
// this should not contain anything related to whatever was written from the earlier iterations....
}
})(request, response);
For the errors you can use the Scripted REST API Error objects.
Which should reset the output stream.
https://developer.servicenow.com/dev.do#!/learn/courses/paris/app_store_learnv2_rest_paris_rest_integrations/app_store_learnv2_rest_paris_scripted_rest_apis/app_store_learnv2_rest_paris_scripted_rest_api_error_objects
(function run(request, response) {
try {
...
} catch (e) {
var myError = new sn_ws_err.ServiceError();
myError.setStatus(500);
myError.setMessage('Something went wrong');
myError.setDetail('Error while retrieving your data: ' + e);
return myError;
}
})(request,response);
It might also be useful to get the error message from the GlideRecord
gr.getLastErrorMessage();
// something like aborted by businessrule or acl, etc...
For the details of your error message.

SSJS Platform.Response.Redirect throws error in Try Catch Statement

I suspect threadabortexception issue of .NET but I couldn't fix it with possible options.
In short Redirect function throws an errors and goes to the catch, no matter to set the second parameter true or false).
The code below is just an example (but I faced this a couple of times before in real-time projects).
...
try {
var TSD = TriggeredSend.Init("DE_Name");
var Status = TSD.Send(data.subscriber, data.attributes);
if (Status != "OK") {
Platform.Response.Redirect(Variable.GetValue("#error_page"));
} else {
Platform.Response.Redirect(Variable.GetValue("#thanks_page")); //<<<-- This redirect throw error
}
} catch (err) {
Platform.Response.Redirect(Variable.GetValue("#error_page")); // <---- here it comes
}
...
Resources might helps:
1# https://support.microsoft.com/en-us/help/312629/prb-threadabortexception-occurs-if-you-use-response-end-response-redir
2# https://developer.salesforce.com/docs/atlas.en-us.mc-programmatic-content.meta/mc-programmatic-content/ssjs_platformClientBrowserRedirect.htm?search_text=Redirect
Any workaround is welcome.
I know this is an older question but I think it would be good to share findings.
There is no logical explanation to me why this is happen but the Redirect always throws an error and if it is used in a try block, the catch part will be executed.
Here is a simple workaround:
...
try {
var TSD = TriggeredSend.Init("DE_Name");
var Status = TSD.Send(data.subscriber, data.attributes);
try {
if (Status != "OK") {
Platform.Response.Redirect(Variable.GetValue("#error_page"));
} else {
Platform.Response.Redirect(Variable.GetValue("#thanks_page")); //<<<-- This redirect throw error
}
} catch(e) {}
} catch (err) {
Platform.Response.Redirect(Variable.GetValue("#error_page")); // <---- here it comes
}
...

Do not execute following code if error callback

I am creating a REST api and I've defined this error handler:
function handleError(res, reason, message, code) {
console.log("ERROR: " + reason);
res.status(code || 500).json({"error": message});
}
But I think it needs some kind of interruption so that the following code is not executed, because if I implement my post method like this:
app.post("/contacts", function(req, res) {
var newContact = req.body;
newContact.createDate = new Date();
if (!(req.body.firstName || req.body.lastName)) {
handleError(res, "Invalid user input", "Must provide a first or last name.", 400);
}
db.collection(CONTACTS_COLLECTION).insertOne(newContact, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to create new contact.");
} else {
res.status(201).json(doc.ops[0]);
}
});
});
The server crashes and the invalid insertion is made into the database. I could solve this problem with an else for the insertion part, but I wanted to know if there is a way of not doing the rest of the method if the function handleError gets called.
Just return after call handleError function
//
if (!(req.body.firstName || req.body.lastName)) {
handleError(res, "Invalid user input", "Must provide a first or last name.", 400);
return;
}
//
A return statement will stop the rest of the function being executed.
Simply edit your handleError function so that the last line will be:
return res.status(code || 500).json({"error": message});
Or, in your /contacts handler :
if (!(req.body.firstName || req.body.lastName)) {
return handleError(res, "Invalid user input", "Must provide a first or last name.", 400);
}
Obvious answer is return or if somewhere higher up in the call stack you have error handling, throwing is also valid flow control, but depending on your use-case, there might be a cleaner method.
I'm guessing you are using express. Check this out.

throwing a debug from chrome extension content script

Short version
Trying to write a debug command that returns the call stack, minus the current position. I thought I'd use:
try {
throw new Error(options["msg"])
} catch (e) {
e.stack.shift;
throw (e);
}
but I don't know how to do it exactly. apparently I can't just e.stack.shift like that. Also that always makes it an Uncaught Error — but these should just be debug messages.
Long version
I decided I needed a debug library for my content scripts. Here it is:
debug.js
var debugKeys = {
"level": ["off", "event", "function", "timeouts"],
"detail": ["minimal", "detailed"]
};
var debugState = { "level": "off", "detail": "minimal" };
function debug(options) {
if ("level" in options) {
if (verifyDebugValue("level", options["level"]) == false)
return
}
if ("detail" in options) {
if (verifyDebugValue("detail", options["detail"]) == false)
return
}
console.log(options["msg"]);
}
function verifyDebugValue(lval, rval){
var state = 10; // sufficiently high
for (k in debugKeys[lval]) {
if (debugKeys[lval][k] == rval) {
return true;
}
if (debugKeys[lval][k] == debugState[lval]) { // rval was greater than debug key
return false;
}
}
}
When you using it, you can change the debugState in the code to suit your needs. it is still a work in progress but it works just fine.
To use it from another content script, just load it in the manifest like:
manifest.json
"content_scripts": [
{
"js": ["debug.js", "foobar.js"],
}
],
and then call it like:
debug({"level": "timeouts", "msg": "foobar.js waitOnElement() timeout"});
which generates:
foobar.js waitOnElement() timeout debug.js:17
And there is my problem. At the moment, it is using the console log and so all the debug statements come from the same debug.js line. I'd rather return the calling context. I imagine I need something like:
try {
throw new Error(options["msg"])
} catch (e) {
e.stack.shift;
throw (e);
}
but I don't know how to do it exactly. apparently I can't just e.stack.shift like that. Also that always makes it an Uncaught Error — but these should just be debug messages.
You can't avoid mentioning the line in your debug.js, because either using throw (...) or console.log/error(...) your debug.js will be issuing the command.
What you can do, is have some try-catch blocks in your code, then in the catch block pass the error object to your debug function, which will handle it according to its debugState.
In any case, it is not quite clear how you are using your debug library (and why you need to remove the last call from the stack-trace, but you could try something like this:
Split the stack-trace (which is actually a multiline string) into lines.
Isolate the first line (corresponding to the last call) that is not part of the error's message.
Put together a new stack-trace, with the removed line.
E.g.:
function removeLastFromStack(stack, errMsg) {
var firstLines = 'Error: ' + errMsg + '\n';
var restOfStack = stack
.substring(firstLines.length) // <-- skip the error's message
.split('\n') // <-- split into lines
.slice(1) // <-- "slice out" the first line
.join('\n'); // <-- put the rest back together
return firstLines + restOfStack;
}
function myDebug(err) {
/* Based on my `debugState` I should decide what to do with this error.
* E.g. I could ignore it, or print the message only,
* or print the full stack-trace, or alert the user, or whatever */
var oldStack = err.stack;
var newStack = removeLastFromStack(oldStack, err.message);
console.log(newStack);
//or: console.error(newStack);
}
/* Somewhere in your code */
function someFuncThatMayThrowAnErr(errMsg) {
throw new Error(errMsg);
}
try {
someFuncThatMayThrowAnErr('test');
} catch (err) {
myDebug(err);
}
...but I still don't see how removing the last call from the trace would be helpful

Casper JS waitForResource with a restful API

We are having a little problem with a functional test with casper.js.
We request the same resource twice, first with the GET and then with POST method.
Now when waiting for the second resource (POST) it matches the first resource and directly goes to the "then" function.
We would like to be able to check for the HTTP method in the "test" function, that way we can identify the resource properly. For now we use the status code (res.status), but that doesn't solve our problem fully, we really need the http method.
// create new email
this.click(xPath('//div[#id="tab-content"]//a[#class="button create"]'));
// GET
this.waitForResource('/some/resource',
function then() {
this.test.assertExists(xPath('//form[#id="email_edit_form"]'), 'Email edit form is there');
this.fill('form#email_edit_form', {
'email_entity[email]': 'test.bruce#im.com',
'email_entity[isMain]': 1
}, true);
// POST
this.waitForResource(
function test(res) {
return res.url.search('/some/resource') !== -1 && res.status === 201;
},
function then() {
this.test.assert(true, 'Email creation worked.');
},
function timeout() {
this.test.fail('Email creation did not work.');
}
);
},
function timeout() {
this.test.fail('Email adress creation form has not been loaded');
});
Or maybe there is a better way to test this scenario? Although since this is a functional test we need to keep all those steps in one test.
You can try to alter the form action url to add some query string, therefore generating a new resource appended to the stack. Could be done this way:
casper.thenEvaluate(function() {
var form = __utils__.findOne('#email_edit_form');
form.setAttribute('action', form.getAttribute('action') + '?plop');
});
That's a hack though, and functional testing should never be achieved that way. Let's hope more information will be added to the response objects in the future.
The res parameter that is passed to the test function has an ID. I created a helper that tests against this ID and blacklists it, so the same resource won't get accepted a second time.
var blackListedResourceIds = [],
testUniqueResource = function (resourceUrl, statusCode) {
return function (res) {
// check if resource was already loaded
var resourceFound = res.url.search(resourceUrl) !== -1;
// check statuscode
if (statusCode !== undefined) {
resourceFound = resourceFound && res.status === statusCode;
}
// check blacklisting
if (!resourceFound || blackListedResourceIds[res.id] !== undefined) {
return false;
} else {
blackListedResourceIds[res.id] = true;
return true;
}
};
};

Categories