Calling http GET requests from ibm cloud functions using nodejs - node.js

while developing the cloud function I got the following error.
i created a cloud action and used that action name inside the json response in watson assistance. then once the intent is matched it call the cloud function. I selected nodejs as developing language of the cloud function.
now my real requirement is to call a https get request from that cloud function. for that i need to use nodejs library called node-rest-client.
normally we need to install it by typing "npm install node-rest-client" in the terminal. since there is no terminal in IBM nodejs editor i got, could you please let me know how to do that.
As a substitute i used https library which is already in nodejs package. and wrote the following code in the editor
const https = require('https');
function main() {
https.get('https://f6054382.ngrok.io/webhook/testRequest', (resp) => {
resp.on('data', (d) => {
process.stdout.write(d);
});
});
}
main();
once I type "node init" in local folder and add the above code to index.js file and then run it using the command "node index.js" code works successfully by giving me the expected output from the webservice.
But I do not get that result in IBM nodejs editor
https://console.bluemix.net/openwhisk/details/action/dialogif.psi%2540gmail.com_dev/webhookCall/code
once i save the above code and invoke by clicking the button in right upper i get the successes response in green as follows.
Activation ID:
341d4e5bc81f4e489d4e5bc81f2e4888
Results:
{}
Logs:
[]
could you please help me to sort this out
Thank you

When executing an asynchronous operation, e.g. HTTP request, you need to return a Promise from the action handler. This ensures the platform will block on that asynchronous result before completing the invocation.
function main() {
return new Promise((resolve, reject) => {
https.get('https://f6054382.ngrok.io/webhook/testRequest', (resp) => {
resp.on('data', (d) => {
process.stdout.write(d);
resolve({})
});
});
})
}

The underlying issue is that your code runs asynchronously and does not return a Promise to indicate a result will be available in the future.
I'd suggest to use the request-promises, which comes pre-packaged with OpenWhisk's Node.js runtime.
const request = require('request-promise');
function main(params) {
return request("https://f6054382.ngrok.io/webhook/testRequest").then(response => {
process.stdout.write(response);
});
}

Related

Having trouble importing an async function into another file

I've been working on a Guilded Bot that automatically runs a function after x amount of MS. My goal is to automate this function to check a website for new posts. The issue I'm encountering is when trying to import the function and call on it within another file. None of the recommended methods I've found seem to work. Below is my code.
//relay.ts under ./automations/
async function patchNotes(message:Message) {
}
export { patchNotes }
//The main file in src its called index.ts
import path from "path";
import { BotClient, Client, Message } from "#guildedjs/gil";
const { token, token2 } = require('./config.json');
import { patchNotes } from './automations/relay';
const client = new BotClient({
token: token,
prefix: "/",
});
client.once('ready', () => console.log('Ready! Shut down using "ctrl+c"'));
client.login();
process.on("unhandledRejection", console.log)
//setTimeout(() => console.log(client.commands), 600);
// Automations
patchNotes
setInterval(() => patchNotes, 6000);
Currently, this method doesn't return console errors for both Types and other stuff. But it also doesn't run the code at all? I've tried other methods too but none have worked so far. Below are what packages I'm using.
ts-node "10.8.1"
typescript "4.7.4"
It's running Node.js and all files are written in TS. If you need any more details, I'd be happy to give them. Really hoping to get past this issue instead of just putting the function in my main file.
So I've actually just found the answer. So it seems I can use setInterval with async tasks. Below is the code I use to achieve this.
setInterval(async () => {
await function();
}, delay)
As for my other issue. I've figured out that I could just write client.messages.send instead of putting message. in front of it. Reason I didn't follow the advice of the recent comment is because this function shouldn't have any values returning. The reason I added message: Message is because there is a line in my code that uses "message". Which is the one mentioned above. Shoulda added that to this thread. Thanks for the response though. Resolved.

Understanding arguments of async javascript method

I am trying to use the ziti-sdk-nodejs, an opensource project, to secure a web application. I have a simple nodejs application that uses express. This application is a hello world demo that is deployed to Azure App Service. I'd like to use the ziti-nodejs sdk to secure my application.
I am trying to use the example shown here.
There is a part of the code that I need help understanding
const zitiHttpRequest = async (url, method, headers) => {
return new Promise((resolve) => {
ziti.Ziti_http_request(
url,
method,
headers,
(obj) => { // on_req callback
console.log('on_req callback: req is: %o', obj.req);
return resolve(obj.req);
},
(obj) => { // on_resp callback
console.log(`on_resp status: ${obj.code} ${obj.status}`);
if (obj.code != 200) {
core.setFailed(`on_resp failure: ${obj.status}`);
process.exit(-1);
}
process.exit(0);
},
(obj) => { // on_resp_body callback
// not expecting any body...
if (obj.len === UV_EOF) {
console.log('response complete')
process.exit(0);
} else if (obj.len < 0) {
core.setFailed(`on_resp failure: ${obj.len}`);
process.exit(-1);
}
if (obj.body) {
let str = Buffer.from(obj.body).toString();
console.log(`on_resp_body len: ${obj.len}, body: ${str}`);
} else {
console.log(`on_resp_body len: ${obj.len}`);
}
});
});
};
I'd like to understand what the arguments (url, method, headers, (obj)...) do. Can someone explain what these arguments mean? I would appreciate if someone could make a tag for open ziti. This is a popular opensource project that allows people to secure their application with a zero-trust network.
#evangertis the sample app you referenced uses an obsolete SDK, namely "ziti-sdk-nodejs": "^0.2.3".
The latest OpenZiti SDK for NodeJS is "#openziti/ziti-sdk-nodejs": "^0.13.3", and I encourage you to migrate to that since it is actively maintained.
Here is a link to the OpenZiti SDK for NodeJS API reference doc.
For more context on this SDK, you may be interested in this article I wrote concerning how to secure NodeJS applications.

NodeJS and ExpressJS app times out with TAP

I'm trying to test an ExpressJS (4.17.8) and NodeJS (16.3) powered server (app) with tap, and later with supertest. First I'm testing the instantiation of the server, and later its routes.
For this, my app is wrapped in a Connector Class that:
has an ExpressJS server (app)
connects to an external system
registers endpoints
has a method startup that calls app.listen
So I have a test file like this:
import test, { Test } from "tape-promise/tape";
test("connects to X", async (t: Test) => {
connector = new Connector();
await connector.ConnectToExternalSystem(); // connects to external system
await connector.registerEndpoints(); // e.g., sets to the Express app: app[get](/endpoint)...
await connector.listen(); // gets stuck?
t.ok(connector);
t.end();
My problem is that for every test I perform, tap seems to get stuck (happens with Jest as well) in connector.listen() - leading for the test to timeout.
My project and tests are written in Typescript 4.3.5. I am using the following npm script to run the tests:
"test": "tap --ts --jobs=1 --node-arg=--max-old-space-size=4096 --timeout=15 --branches=45 --functions=70 --lines=75 --statements=75 \"src/test/{unit,integration}/\"",
Is there anything I'm doing wrong? Appreciate your advice on this.
Thanks.
Depends on what the implementation of Connector really looks like. Assuming that the .listen() method of it calls express' listen under the hood the issue might be that you are not handling the success callback or that it's not wired up properly to the returned promise via the resolve callback of the promise.
So something like this could work (rough pseudo code, not tested):
class Connector {
listen(): Promise<void> {
return new Promise((resolve, reject) => {
this.expressApp.listen((err: Error) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
}
What the above does is ensures that the returned promise resolves once the callback has been invoked (or rejects if the callback was passed in an error which is the standard NodeJS error handling style)

How to run a node async function locally?

I'm attempting to write a Node async function and run test it locally. I have this function (using nano for CouchDB):
async function calldb() {
console.log("entering calldb")
const q = {
... query def ...
};
try {
console.log("before await")
const response = await nano.db.find(q)
console.log("after await")
} catch (e) {
return { Error: e}
}
console.log(response);
return response;
}
I want to test locally, so I'm doing npx run-func getGoods.js calldb. This yields:
npx run-func index.js calldb
npx: installed 1 in 0.91s
entering calldb
before await
The first console log runs, but then it doesn't wait around for the response from the db.
How can I test this locally to see if I am actually connecting to the Couch database? How can I get the return from the db call to log to console?
If you look at the code of the library that you indicate (https://github.com/DVLP/run-func/blob/master/index.js), it does not wait for an async function.
If you want to use that library you would need to change the code.

Replicating "Concourse CI" Node Call / Debugging process.stdin Net.socket

I've built a customer resource using node. The resource code looks okay, but once compiled and placed into Concourse, the "Check" in the resource is failing.
Concourse is not giving any useful information except "Unexpected end of JSON"
I'd like to replicate exactly how Concourse calls the build, but I don't know how to find out what it calls?
My assumption was /opt/resource/check which has #!/usr/bin/env node
so just calling this should be sufficient, but I do not get the same behavior.
What I can determine is that it's hanging on my socket that fetches the params passed via stdIn, code below:
export async function retrieveRequestFromStdin<T extends any>(): Promise<T> {
return new Promise<T>((resolve, reject) => {
let inputRaw = "";
process.stdin.on("data", (chunk) => {
process.stdout.write(chunk);
inputRaw += chunk;
});
process.stdout.write(inputRaw);
process.stdin.on("end", async () => {
try {
const json = JSON.parse(inputRaw) as T;
if (!json.source.server_url.endsWith("/")) {
// Forgive input errors and append missing slash if the user did not honor the docs.
json.source.server_url = `${json.source.server_url}/`;
}
resolve(json);
} catch (e) {
reject(e);
}
});
});
}
This is the check code:
(async () => {
try {
const request: ICheckRequest = await retrieveRequestFromStdin<ICheckRequest>();
// Removed unnecessary items
} catch (e) {
stderr.write(e);
process.exit(1);
}
})();
How do I call a NodeJS script the same way as Concourse, so I can find out exactly what the problem is?
Note, I'm compiling Javascript from Typescript
For a resource check, Concourse will run /opt/resource/check passing in the source information from the resource configuration in on stdin. For example, if you configured the pipeline with:
resources:
- name: resource-name
type: your-new-node-resource-type
source:
server_url: https://someurl.com
the first time check runs, your script would receive this on stdin:
{"source": {"server_url": "https://someurl.com"}}
Your script is then expected to return the "current" version of the resource on stdout. In the example below, I've named the key version-example, but you can name that anything you want. You can also add other keys too if you want. This allows you flexibility in uniquely identifying a version.
[{"version-example": "46"}]
Subsequent calls from Concourse to your check script will also include the latest version it knows about, so continuing the example, the next call will pass this to your script:
{"source": {"server_url": "https://someurl.com"},
"version": {"version-example": "46"}}
Your check script should now return (on stdout) an array of any new versions that it finds in order:
[{"version-example": "47"},
{"version-example": "48"},
{"version-example": "49"}]
For more details, you can check out the official docs, which should also be useful when implementing the in and out scripts.
Taking a quick look at your code, it seems that it's writing stdin twice to stdout, which results in the Unexpected end of JSON message. e.g.:
{"source": {"server_url": "https://someurl.com"}}
{"source": {"server_url": "https://someurl.com"}}

Resources