Page 1 of 1

api call from flow

Posted: Tue Sep 01, 2020 10:14 am
by Sunnyland
I am currently trying to make an api call from a flow. I already have a script that works using Javascript but for this I have decided to put my poor NodeJs skills to the test and see how I go. I have failed so far, it appears that the http code is just ignored by switch. I do not get success logs or error logs and in debug mode it just jumps over the code.
Below I have shared my code, you will notice I have both http and axios in the code, basically I was just trying both to see if one would work. Originally I just had http but expanded when I could not get it to work.
Help will be appreciated.

const http = require("http");
const axios = require('axios');
const DomPaser = require("xmldom").DOMParser;
const XPath = require("xpath");
const fs = require("fs-extra");

async function jobArrived(s, flowElement, job) {

let jobName = await job.getName();

const tempPath = await job.getDataset("knifedata", AccessLevel.ReadOnly);
const content = await fs.readFile(tempPath, { encoding: "utf8" });

var doc = new DomPaser().parseFromString(content);

var value = await XPath.select("//value",doc);

await job.log(LogLevel.Info, jobName);
let filename = jobName;

let data = JSON.stringify({ details: { "knifenumber": value[0].firstChild.data, "filename": filename, "description1": isEmpty(value[2]), "description2": isEmpty(value[3]), "description3": isEmpty(value[4]), "jobnumber":value[1].firstChild.data} })

let options = {
hostname: "myhost",
port:80,
path: "/api/iq/NewKnife",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(data)
}
}

axios
.post('myhost/api/iq/NewKnife', {
item: data
})
.then(res => {
job.log(LogLevel.Info,"statusCode: %1",[res.statusCode])
job.log(LogLevel.Info,res)
})
.catch(error => {
job.error(LogLevel.Info,error)
})

http.request(options, res => {
job.log(LogLevel.Info,"statusCode: %1",[res.statusCode])
res.on('data', d => {
data += d
})
res.on("end", () => {
console.log(data)
})
.on("error", console.error)
.end(data)
})

await job.sendToSingle();
}

var isEmpty = function(value) {
if (value.firstChild) {
return value.firstChild.data;
}else{
return "";
}
}

Re: api call from flow

Posted: Fri Oct 02, 2020 9:07 am
by freddyp
You are using callbacks for the http part, but Switch keeps executing the rest of the script and hits the end before the http call calls the callback function (lots of calling going on here).

We are organizing webinar sessions on NodeJS scripting in Switch on October 20th and 22nd (Getting started) and on November 17th and 19th (Advanced). Keep an eye on your mailbox for the invitations with the times and registration details.

One of the things that will be mentioned several times during these sessions: USE PROMISES!

Re: api call from flow

Posted: Fri Oct 02, 2020 9:17 am
by Sunnyland
Thanks Freddy,
Yep big learning curve with NodeJS, using callback or Promises. I really had to drill down on what the differences are. I have change the above code and now it uses promises and not callbacks and believe it or not the code is much simpler and now works.

Will look forward to the webinar.

Re: api call from flow

Posted: Sat Jan 16, 2021 2:45 pm
by foxpalace
Hi,
can you post, what you changed?

Re: api call from flow

Posted: Sun Jan 17, 2021 10:42 pm
by Sunnyland
Hi Foxplace,
This is the code I used to send the SOAP request and to return as a promise.

const options = {
hostname: nURL.hostname,
port: 443,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length,
'Host' : nURL.hostname
}
}

return new Promise((resolve, reject) => {
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
let body = '';
res.on('data', (chunk) => (body += chunk.toString()));
res.on('error', reject);
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode <= 299) {
resolve({statusCode: res.statusCode, headers: res.headers, body: body});
} else {
reject('Request failed. status: ' + res.statusCode + ', body: ' + body);
}
});
});

req.on('error', reject);
req.write(data, 'binary');
req.end();

});

Hope this helps

Re: api call from flow

Posted: Sun Jan 17, 2021 10:49 pm
by Sunnyland
This is what the above code looks with these changes.

const querystring = require('querystring');
const http = require("http");
const XPath = require("xpath");
const fs = require("fs-extra");
const DomPaser = require("xmldom").DOMParser;

async function jobArrived(s, flowElement, job) {

let jobName = await job.getName();

const tempPath = await job.getDataset("knifedata", AccessLevel.ReadOnly);
const content = await fs.readFile(tempPath, { encoding: "utf8" });

var doc = new DomPaser().parseFromString(content);

var value = await XPath.select("//value",doc) //Get Title and Clean

await job.log(LogLevel.Info, jobName);
let filename = jobName;

let data = JSON.stringify({ details: { "knifenumber": value[0].firstChild.data, "filename": filename, "description1": isEmpty(value[3]), "description2": isEmpty(value[4]), "description3": isEmpty(value[5]), "knifecategory": isEmpty(value[1]), "jobnumber":value[2].firstChild.data} })

try{
await UpdateDieLibary(data);
} catch(e){
console.log(e);
}
await job.sendToSingle();
}

async function UpdateDieLibary(data) {

let options = {
hostname: 'myhost',
port:80,
path: '/api/iq/NewKnife',
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(data)
}
}

return new Promise((resolve, reject) => {
const req = http.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
let body = '';
res.on('data', (chunk) => (body += chunk.toString()));
res.on('error', reject);
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode <= 299) {
resolve({statusCode: res.statusCode, headers: res.headers, body: body});
} else {
reject('Request failed. status: ' + res.statusCode + ', body: ' + body);
}
});
});

req.on('error', reject);
req.write(data, 'binary');
req.end();
});



}

var isEmpty = function(value) {
if (value.firstChild) {
return value.firstChild.data;
}else{
return "";
}
}

Re: api call from flow

Posted: Mon Jan 18, 2021 9:05 am
by freddyp
@Sunnyland: you can make the HTTP part of your code simpler based on the advice I gave in this post: viewtopic.php?f=26&t=3959