Azure Functions NodeJS: Https Request not working when using Azure Visual Studio Code Extension - node.js

I am working with Azure Functions in NodeJS. I first wrote the function having azure funct locally on my laptop. The code worked fine and did everything I wanted. Now, I added the code to a new azure function in my Azure Visual Studio Code Extention - the exact same code. BUT now it does not work anymore. I don't get an error or something, the https request is just not started.
Here is my code:
const https = require('https');
const fs = require('fs');
const storage = require('azure-storage');
const STORAGE_ACCOUNT_NAME = 'SOMETHING';
const ACCOUNT_ACCESS_KEY = 'SOMETHING';
const blobService = storage.createBlobService(STORAGE_ACCOUNT_NAME, ACCOUNT_ACCESS_KEY);
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
let _browser;
let _page;
https.get(SOMEURL", (resp) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', async () => {
context.log('here');
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
};
It never prints the "here" which should be done after the https request ends. (The first context.log is however printed in both cases)
So my question is, what am I doing wrong? Can I not use https request inside azure functions when using the visual studio code extension?
Edit:
anyone who needs the async, here is a link explained how to do it with util.promisify: https://gist.github.com/krnlde/797e5e0a6f12cc9bd563123756fc101f

I've kept your code callback based.
I removed the async moniker from the definition and added a call to context.done (this signals the functions host when your function has ended) in your resp.end handler
const https = require('https');
const fs = require('fs');
const storage = require('azure-storage');
const STORAGE_ACCOUNT_NAME = 'SOMETHING';
const ACCOUNT_ACCESS_KEY = 'SOMETHING';
const blobService = storage.createBlobService(STORAGE_ACCOUNT_NAME, ACCOUNT_ACCESS_KEY);
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
let _browser;
let _page;
https.get(SOMEURL", (resp) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', async () => {
context.log('here');
context.done();
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
};
Another option would be to keep the function as async but you'd need to replace the callbacks with promise based calls. In some scenarios this can be achieved by wrapping them using util.promisify and then calling them with the await keyword

Related

Dialogflow is giving error unreachable code after return

I'am fetching the data via axios from mini crypto compare api for getting the crypto prices in dialogflow, but in my fulfillment code I'am receiving this error (if unreachable code after return). If I bring the if section inside the promise, than the agent.add() will not work and it give no response defined for the platform error in the console.
function priceFinder(agent) {
const data = agent.parameters[CRYPTO_NAMES];
let btc = '';
let eth = '';
return axios.get('https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH,BNB,SOL,LUNA&tsyms=USD')
.then(response => {
btc = response.data.BTC.USD;
eth = response.data.ETH.USD;
});
if(data === "btc") {
agent.add(`BTC Price is : ${btc}`);
}
else if(data === "eth") {
agent.add(`ETH Price is : ${eth}`);
}
}
I was able to get your function working on my side, here is my updated code to your function based on the block you provide:
used library
const https = require('https');
main function
function getBitcoinInfo(agent){
const url= 'https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH,BNB,SOL,LUNA&tsyms=USD';
const req = https.get(url, res => {
console.log(`statusCode: ${res.statusCode}`);
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(data);
console.log(JSON.parse(data).BTC);
});
});
agent.add(`I found bitcoins!`);
}
IntentMap
let intentMap = new Map();
intentMap.set('Get Bitcoin Info', getBitcoinInfo);
agent.handleRequest(intentMap);
Useful Tips
return will execute that last statement and will not proceed further effectively making the rest code lines unreachable.
You can check the logs on by going to cloud functions -> my_deployed_ fullfillment -> logs
Latest results are always show at the end.
If no console message reach the log, make sure your function executes properly
Once you parse the json you can pick elements from it and fill variables and add it to your response. You can use JSON parse for it.
Useful links:
http-requests

Node js extract data from a nested function

I am trying to process signup data for a uni project . I am using basic koa modules and I am not allowed to use express, ideally I want to get the data inside the variable post. I want to process the data for example to see if the password has less than 5 characters , if so i would like that the program would not redirect the user to different address but if no errors occur i would like the program to redirect to regOk.html, I tried many other ways like initializing the variable outside of ctx.req.on but none were successful . Can anyone help me ?
export async function postregister(ctx) {
let bodyString = "";
ctx.req.on("data", (chunk) => {
bodyString += chunk;
});
//let collectData = new Array();
ctx.req.on("end", () => {
var post = querystring.parse(bodyString);
var email = post["email"];
var password = post["password"];
var passbestätigen = post["passwort bestä"];
var vorname = post["vorname"];
var nachname = post["nachname"];
var adresse = post["adresse"];
var stadt = post["stadt"];
var telefonnummer = post["telefonnummer"];
var geburtsdatum = post["geburtsdatum"];
var regData = model.add(ctx.db, post);
regData.then(() => console.log("singup successful"))
});
await ctx.render("regOk.html");
}
I'm not very familiar with koa, but I believe your issue is related to the order in which your code is executed.
The event in charge of parsing the data received in the body of the request ends after the synchronic execution of your postregister method, so you never get to see the value of post in the order you'd expect.
One possible solution to go around this issue would be wrapping the parsing of data in a promise, waiting for that promise to complete, and executing then and catch functions once the processing is done.
export async function postregister(ctx) {
await new Promise((resolve) => {
let bodyString = "";
ctx.req.on("data", (chunk) => {
bodyString += chunk;
});
ctx.req.on("end", async () => {
resolve(querystring.parse(bodyString));
});
})
.then(async (post) => {
await model.add(ctx.db, post)
.then(async () => {
console.log("singup successful");
await ctx.render('regOk.html');
});
})
.catch(async (error) => {
console.error(error);
await ctx.render('error.html');
});
}
This way, you handle body parsing inside the Promise, and after that completed you get the result of querystring.parse(bodyString) as a variable named post in your then handler.

Why is it not going inside the function? It only output "finish" and "start" on AWS Lambda

I'm doing a html to pdf function using the phantom-html-to-pdf on AWS Lambda with NodeJS. But I encountered a problem that did not go inside the function. The output only shows Start, Finish and Done is not shown which means it's not going in the function. What is the issue here?
var fs = require('fs')
var conversion = require("phantom-html-to-pdf")();
exports.handler = async (event) => {
console.log("Start")
conversion({ html: "<h1>Hello World</h1>" },
async(err, pdf) => {
var output = fs.createWriteStream('output.pdf')
console.log(pdf.logs);
console.log(pdf.numberOfPages);
// since pdf.stream is a node.js stream you can use it
// to save the pdf to a file (like in this example) or to
// respond an http request.
pdf.stream.pipe(output);
console.log("Done")
});
console.log("Finish")
};
The problem is you have marked your lambda function as async which means your function should return a promise. In your case you are not returning a promise. So you have two choices here
Convert the conversion function from callback to promise based.
OR instead of marking the function async, add callback and execute that. something like this
const fs = require("fs");
const conversion = require("phantom-html-to-pdf")();
exports.handler = (event, context, callback) => {
console.log("Start");
conversion({"html": "<h1>Hello World</h1>"},
// eslint-disable-next-line handle-callback-err
async (err, pdf) => {
const output = fs.createWriteStream("output.pdf");
console.log(pdf.logs);
console.log(pdf.numberOfPages);
// since pdf.stream is a node.js stream you can use it
// to save the pdf to a file (like in this example) or to
// respond an http request.
pdf.stream.pipe(output);
console.log("Done");
callback(null, "done");
});
};

IBM Action not returning anything after GET request

First of all, I am a beginner in Javascript, so if there are any uncertainities or unclarities in my message, please feel free to correct me.
I try to create an action to support my IBM Watson Assistant. Once called, the action should get some info from a http and give some answer back.
The "get" action was part of a Webhook, successfully deployed via Heroku as support for Dialogflow. I just changed it a little bit, to make the answer easier.
function main(req){
const http = require('http');
const API_KEY = '85324cac';
const prodname = req.prodname;
const reqUrl = encodeURI(`http://www.omdbapi.com/?t=${prodname}&apikey=${API_KEY}`);
http.get(reqUrl, (responseFromAPI) => {
let completeResponse = '';
responseFromAPI.on('data', (chunk) => {
completeResponse += chunk;
});
responseFromAPI.on('end', () => {
const movie = JSON.parse(completeResponse);
let dataToSend = prodname ;
dataToSend += (typeof movie.Title === "undefined") ? `Sorry the film is not in our database` : `${movie.Title} is a ${movie.Actors} starer ${movie.Genre} movie, released in ${movie.Year}. It was directed by ${movie.Director}.`;
return {answer: dataToSend};
});
});
//return {answer: dataToSend};
}
I was expecting an answer after the "return" action, but it is only showing empty values. I am pretty sure that the action does never get into the "http.get" part. When I remove the // and I invoke the code, it returns the following message: "dataToSend is not defined"; if I keep code as it is (with the comment), no errors pop up.
The omdapi is for free, but hosted in the US, in case that could matter.
Any ideas? In any case, thanks in advance.
Think you will find that your ibm function is completing before your external call to omdbapi is returning. Your best choice here is to use promises ( being new I expect you may not have used promises yet - would recommend reading https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-creating-javascript-actions#creating-javascript-actions
Not your complete program, leave you something to play with;
function main(req){
const http = require('http');
const API_KEY = '85324ca';
//const prodname = req.prodname;
const prodname = 'Game%20of%20Thrones&Season=1';
const reqUrl = 'http://www.omdbapi.com/?t=Game%20of%20Thrones&Season=1&apikey=85324cac';
//const reqUrl = encodeURI(`http://www.omdbapi.com/?t=${prodname}&apikey=${API_KEY}`);
return new Promise(function(resolve, reject) {
http.get(reqUrl, (responseFromAPI) => {
let completeResponse = '';
responseFromAPI.on('data', (chunk) => {
completeResponse += chunk;
// you could return answer here via resolve.
//var parsedData = JSON.parse(completeResponse);
//console.log(parsedData);
//resolve(parsedData);
})
responseFromAPI.on('error', (error) => {
console.log(error);
reject(error);
})
responseFromAPI.on('end', () => {
var parsedData = JSON.parse(completeResponse);
console.log(parsedData);
resolve(parsedData);
});
});
});
}

AWS Lambda function to check whether the site is available

I want to create an AWS Lambda function to check whether the site is available. I tried this function.
'use strict';
var url = require('url');
var target = 'https://www.google.com'; // Change this one
exports.handler = function(event, context, callback) {
var urlObject = url.parse(target);
var mod = require(
urlObject.protocol.substring(0, urlObject.protocol.length - 1)
);
console.log('[INFO] - Checking ' + target);
var req = mod.request(urlObject, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log('[INFO] - Read body chunk');
});
res.on('end', function() {
console.log('[INFO] - Response end');
callback();
});
});
req.on('error', function(e) {
console.log('[ERROR] - ' + e.message);
callback(e);
});
req.end();
};
I tried this in "How it works" section before create the actual function. But when I run this, I get an error "Process exited before completing request"
My objective is to send an alert if the site is down (using AWS cloud-watch).
Your code terminates because you're invoking req.end before any the events are invoked. Under the hood, these APIs use the EventEmitter API in NodeJS so it publishes events to the channels that are listening to them, but since all of this happens asynchronously, req.end is being invoked before any of these events are fired.
You can greatly simplify your code by using the request module. Just pack it with your dependencies.
I have refactored your code a little bit to use async/await as well, so I needed to promifisy the callback. It's a good practice to do so. If you want to send a notification when something goes wrong, just put the code inside the catch block.
'use strict';
const target = 'https://www.google.com'; // Change this one
const request = require('request')
const handler = async (event) => {
try {
const data = await new Promise((res, rej) => {
request.get(target, (err, data) => {
if (err) {
return rej(err)
}
return res(data)
})
})
console.log(data)
} catch (e) {
console.log(e)
//send notification
}
};

Resources