Node - Throw SOAP error on an promise catch block - node.js

I am developing an SOAP Server in NodeJS (v6.9.4) using the SOAP library. I have to request some data from a Postgres database. I choose to use the pg-promise lib.
SAOP Services are implemented like this :
TestConnection: function (args, cb, headers, req) {
db.any("select * from users where active=$1", [true])
.then(function (data) {
return {};
})
.catch(function (error) {
throw {
Fault: {
faultcode: faultCode,
faultstring: faultString,
detail: {
"ns:FaultInformation": {
"ns:FaultCode": detailedFaultCode,
"ns:FaultText": detailedFaultText
}
},
statusCode: 500
}
};
});
}
In case of error during the database connection/request, I need to return a SOAP Fault. On the SOAP lib, you can do this by throwing a new Fault object.
In this example, I want to throw it in the catch block. I know it's not the right way to do this and I am facing this issue :
UnhandledPromiseRejectionWarning: Unhandled promise rejection
(rejection id: 3): [object Object]
How can I throw my SOAP Fault exception in the main service function. I tried without success the setTimeout solution. Is the promise a good solution for PG queries ?

I found a solution myself by using the soap callback function (cb) provided by the soap lib. The following code should return a Soap Fault exception under an Async service implementation :
TestConnection: function (args, cb, headers, req) {
db.any("select * from users where active=$1", [true])
.then(function (data) {
cb({});
})
.catch(function (error) {
cb({
Fault: {
faultcode: faultCode,
faultstring: faultString,
detail: {
"ns:FaultInformation": {
"ns:FaultCode": detailedFaultCode,
"ns:FaultText": detailedFaultText
}
},
statusCode: 500
}
});
});
}

Related

How to handle UnhandledPromiseRejectionWarning

This bit of code, after connecting, does some stuff
controller.connect((response)=>{ does some stuff })
Down deep in the guts of the connect method this async function gets called, which returns a promise by way of the callback
async function ServerSend(endpoint,params,callback) {
const response = axios.get(host+endpoint, {params})
callback(response);
}
If the server is not available it correctly throws: UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:8088
What is the correct way to handle this exception? I could possibly add a catch in the async method and rewrite all the call backs to return an err. But I'd rather catch it at the caller. I have not been able to get either method to work.
axios.get(host+endpoint, {params}) // this is a promise
so if it resolves it will be ok, but if it rejects (and yuou dont have any try .. catch, any .catch attached - it will throw error that exception is unhandled.
Why way would be to:
async function ServerSend(endpoint,params,callback) {
try {
const response = await axios.get(host+endpoint, {params})
callback(null, response);
} catch (err) {
callback(err, null);
}
}
OR
function ServerSend(endpoint,params,callback) {
// most callbacks are two parameters - 1st erro or null, second data if no error is present.
axios.get(host+endpoint, {params}).then(data => callback(null, data)).catch(err => callback(err, null));
}

Adonis has detected an unhandled promise rejection, which may cause undesired behavior in production

You are using adonisJS in a health check service and are trying to make two requests according to axes in a Service. I get a warning from Adonis "Adonis has detected an unhandled promise rejection, which may
cause undesired behavior in production "and my scheduler that monitors this service every 3 minutes just for. What's wrong with my call and why does adonis complain about it?
My strategy was to make a post for a route without login and right after doing a get for a logged route. I take the request token from the post and play it in the request header, but adonis gives me this warning. What is it?
App/Services/JaiminhoService
try {
await axios.post(Env.get('JAIMINHO_URL'), data).then(response => {
if(response.status === 200) {
try {
await axios.get(`${Env.get('JAIMINHO_URL')}/push/schedule/`, {
headers: { Authorization: `Bearer ${response.data?.token}` }
}).then(response => {
if(response.status === 200) {
return {
status: response.status,
message: response.statusText,
service_name: jaiminho,
date,
}
}
})
} catch (error) {
return 'Error'
}
}
else {
//send mail
}
})
return
} catch (error) {
return {
message: 'Error! Please check Jaiminho service.',
service_name: jaiminho,
date
}
}
Warning: Adonis has detected an unhandled promise rejection, which may
cause undesired behavior in production.
To stop this warning, use catch() on promises or wrap await
calls inside try/catch.
Since you are using async/await, you could avoid nesting the .then() calls.
I recommend you to change your code to something like this and see what happens:
try {
const postResponse = await axios.post(Env.get('JAIMINHO_URL'), data);
if (postResponse.status === 200) {
const getResponse = await axios.get(`${Env.get('JAIMINHO_URL')}/push/schedule/`, {
headers: { Authorization: `Bearer ${postResponse.data?.token}` }});
if (getResponse.status === 200) {
return {
status: response.status,
message: response.statusText,
service_name: jaiminho,
date
};
}
} else {
//send mail
}
} catch (error) {
return {
message: 'Error! Please check Jaiminho service.',
service_name: jaiminho,
date
};
}

How to handle a promise with a callback with nodejs?

I'm making an app using the nano npm module with nodejs, one of my async functions is intended to create an object in Cloudant but I'm not pretty sure how to handle a Promise.resolve with a callback which is an important part of the response which is supposed my server has to respond.
I do well with creating the document but the next part is to check if there was an error trying to do it, so if there is an error I'd like my server to return an object with the classic error message.
This is my code:
exports.createMeeting = async (body) => {
var response;
object = {"name": "Billy Batson"}
console.log("-------------")
//Trying to insert the document
response = await Promise.resolve(db.insert(object).then((body, err) => {
//This is the part I'm trying to check if the db.insert did fail
if (err) {
response = {
message: 'Failure',
statusCode: '500',
}
console.log(JSON.stringify(response));
} else {
response = {
message: 'Ok',
statusCode: '201',
}
console.log(JSON.stringify(response));
}
}));
}
console.log("******* ", JSON.stringify(response));
return response;
}
If I try to run this code the output is:
-------------
{"message":"Ok","statusCode":"201"}
******* undefined
The first printed object is because the code reached the part where I assign the response object with the status code 201 but the second part doesn't recognize the value of 'response' and the line "return response;" actually doesn't return it, I've confirmed it with postman (it doesn't get a response).
I think the problem here is that I'm not handling correctly the .then() syntax, I've tried changing to a classic callback with:
response = await Promise.resolve(db.insert(object),(body, err) => {
if (err) {
response = {
message: 'Failure',
statusCode: '500',
}
console.log(JSON.stringify(response));
} else {
response = {
message: 'Ok',
statusCode: '201',
}
console.log(JSON.stringify(response));
}
});
But it prints:
-------------
******* {"ok":true,"id":"502c0f01445f93673b06fbca6e984efe","rev":"1-a66ea199e7f947ef40aae2e724bebbb1"}
Which means the code is not getting into the callback (it's not printing 'failure' or 'ok' objects)
What I'm missing here?:(
nano provides promise-based API when a callback is omitted.
This is not how errors are handled in promises. then callback has 1 parameter, there
will be no err.
It's expected that a promise is rejected in case there's an error. Promise.resolve is redundant when there's already a promise and is always redundant with async..await.
It should be:
try {
const body = await db.insert(object);
response = {
message: 'Ok',
statusCode: '201',
}
} catch (err) {
response = {
message: 'Failure',
statusCode: '500',
}
}

Why is the error not being caught in this NodeJS async function?

I am trying to understand why the catch block in the upload function does not capture the exception thrown after the request(.....) line in createReleaseVersion function.
The nodejs script crashes and the exception is unhandled. Only the error of the exception is shown in the console.
In the following code, I expected to be printed 'got you' then 'after', but it does not happen.
If I replace throw with return reject (... same object) then I get the desired output.
I get first printed 'got you' then 'after'
function createReleaseVersion(releaseVersion) {
var options = {
uri: 'https://someurl',
method: 'POST',
json: {'version': releaseVersion}
};
return new Promise(function(resolve, reject) {
request(options, function (error, response, body) {
throw {
error: error,
response: response,
body: body
};
console.log(body);
if (error) {
throw {
error: error,
response: response,
body: body
};
} else {
resolve();
}
});
});
}
async function upload(releaseVersion) {
try {
await createReleaseVersion(releaseVersion);
} catch (error) {
console.log('got you');
}
console.log('after');
}
upload('ddd');
Well, let's take a simpler case:
new Promise((resolve, reject) => {
setTimeout(() => { throw new Error(); });
});
Which crashes the process. The reason is that the setTimeout (or request in your case) subscribes a callback to be called later.
When the callback is eventually called - the promise constructor is done executing already and the error is thrown into the current context (setTimeout/request's).
The reason the promise constructor catches errors synchronously is because it basically does this:
try {
executor(resolve, reject); // your code
} catch (e) {
reject(e);
}
Because in your case the function does not execute synchronously - it has no way to know about the exception's context. This might change in the future with Zones but probably will not.
If you want to mark an error inside a promisified function - you can call the second argument (reject) and reject(new Error(...)).
I warmly recommend you use util.promisify instead of converting APIs to promises manually to avoid these sort of issues :)
I also recommend you only reject with Error objects for better stack traces.

Meteor : Retrieve value in Meteor.call which calls a server method having promise

I have an internally maintained npm package myNpmPackage which exports a function (for e.g. fnTestMicroSerConn ) as below:
const rp = require('request-promise-native')
exports.fnTestMicroSerConn = function () {
return new Promise(function(resolve, reject) {
var options = {
method: 'GET',
uri : "http://example.net",
resolveWithFullResponse: true,
}
rp(options)
.then(function (response) {
if (response.statusCode !== 200){
console.error("http not 200 but : ",response.statusCode)
resolve(false)
} else {
console.info("connected successfully : "+response.body)
resolve(response)
}
})
.catch(function (err) {
console.error("Error in establishing connectivity : ",err)
resolve(false)
})
})
}
I then need to call the above exported function from a Meteor method like so:
import { Meteor } from 'meteor/meteor';
import myNpmPackage from 'myNpmPackage';
Meteor.methods({
foo: function () {
myNpmPackage.fnTestMicroSerConn().then(function (response){
console.log(" My response: ",response.body);
return(response.body)
})
}
});
console.log(" My response: ",response.body); gets executed successfully and I can see the expected value in the server console log. So till here it's good.
However, now I want to pass the value of response.body to the client side. In short, when I do below on the client :
Meteor.call("foo", function (err, response) {
console.log("calling foo");
if(!err){
console.log("response : ",response);
} else {
console.log("err : ",err);
}
})
Unfortunately, currently I am getting undefined on the client for console.log("response : ",response);
Note: I am using the Meteor Promise package from here
Let me know if any more details are needed or any thing is unclear. I am very new to the Promise style of coding, hence, this can sound as a noob question.
Meteor methods called from clients by Meteor.call run synchronously to prevent clients from pending, even if a callback is supplied.
Your foo method does not wait for that promise inside. It runs past fnTestMicroSerConn() call without hesitation and ends up with no more statement to execute, returning undefined as a result. By the time the promise resolved and logged the expected message on the server console, the method had been exited.
To get resolved/rejected result of that promise, you can return the promise from the method to the caller, and the client would be able to respond to the promise.
Meteor.methods({
foo: function () {
return myNpmPackage.fnTestMicroSerConn();
}
});
Meteor.call("foo")
.then( response => console.log("My response: ", response.body) )
.catch( err => console.log("err : ",err) );
Meteor methods is powerful. The API documentation of methods contains much information and is worth mastery.

Resources