I'm currently deploying this cloud function to my firebase app and I will be using the Node v8 runtime, so I can use the async/await syntax.
I'm having some trouble handling different kinds of errors that may occur in the same function.
When completed, the function should receive a url parameter to make request to that url, scrape the response body for some data and save it to the database. At this point, it is just returning the same url string that it received for testing purposes.
So far, this is what I have:
const functions = require('firebase-functions');
const request = require('request');
const cheerio = require('cheerio');
exports.getDataFromUrl = functions.https.onCall((data) => {
// PROMISIFIED REQUEST TO USE WITH ASYNC AWAIT
const promisifiedRequest = function(options) {
return new Promise((resolve,reject) => {
request(options, (error, response, body) => {
if (error) {
return reject(error);
}
return resolve(response);
});
});
};
// CHECK IF URL IS PRESENT, IF NOT, THROW ERROR
if (!data.url) {
throw new functions.https.HttpsError('invalid-argument','The URL parameter was invalid.');
}
// URL passed from the client.
const url = data.url;
// IIFE ASYNC FUNCTION
(async function() {
// TRY BLOCK
try {
// REQUEST OPTIONS TO THE URL
const urlOptions = {
url: 'https://www.someINEXISTENT.url',
method: 'GET',
gzip: true,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36'
},
jar: true
};
// CREATE RESPONSE AND CHEERIO OBJECT
let response = null;
let $ = null;
// SEND REQUEST TO URL, AND PARSE WITH CHEERIO
response = await promisifiedRequest(urlOptions);
$ = cheerio.load(response.body);
} // TRY BLOCK - END
// CATCH BLOCK
catch (error) {
console.log('Caught an error: ' + error);
throw new functions.https.HttpsError('unknown', error.message, error);
}
console.log('End of async function...');
})()
return {
yourUrl : url
};
});
My first error case, which happens when the URL is invalid is working just fine. The execution stops when I throw the following error:
throw new functions.https.HttpsError('invalid-argument','URL invalid.');
As far as I understood, a need to throw this HttpsError
in order to be able to catch in on the client. And it works. I get this error on the client, when it happens.
My problem is on the second type of error, which should be caught by the try/catch statement inside my async function. That error should happen when I try to request an inexistent url, for example.
What is happening is this (picture below):
The catch block is activated and I can see the `console.log() on my function console, but somehow it doesn't throw the error, and it complains about "throwing inside an async function without a catch block", even though I'm trowing it from inside a catch block. My client code does not get this error at all. From my client's perspective, the function completes without any errors.
Error:
error: (node:5160) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async fnction without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
I have tried adding and outer try/catch
blocks. And also using .catch()
after the async IIFE to throw the error outside the async function, but it didn't solve the problem.
What am I doing wrong?