Google firebase callable web functions - returns {data: null}

Viewed 116

I am currently trying to return some data from a mongodb database query using callable web firebase functions. The functions are called. However, the fullName function returns {data: null} in my browsers console.

I have also tried return "test" and that also returns the same value of {data: null}

I am completely unsure why this is. And when I attempt to console.log

            const data = {
                totalInfections: totalInfections,
                totalUsers: totalUsers,
                totalCommands: totalCommands,
                totalLiveInfections: totalLiveInfections,
                totalLiveInfectedChannels: totalLiveInfectedChannels
            }
            console.log(data)
            return data

Nothing comes up in my function logs (on my localhost), or in my terminal.

However, if I go to http://localhost:5001/pandemic-8955f/us-central1/fullName I get an error in my function logs which is

function[us-central1-fullName]
{
  "severity": "WARNING",
  "message": "Request has invalid method. GET"
}
function[us-central1-fullName]
{
  "severity": "ERROR",
  "message": "Invalid request, unable to process."
}

function[us-central1-fullName]
Finished "us-central1-fullName" in ~1s

I am unsure why this is occuring, and any pointers or advice would be very helpful.

exports.fullName = functions.https.onCall((lol, lol1) => {
    var MongoClient = require('mongodb').MongoClient;
    var url = "mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false";
    MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo = db.db("discord_pandemic");
        dbo.collection("ArrayStats").find().toArray(function(err, result) {
            if (err) throw err;
            const totalInfections = result[0].total_infections
            const totalUsers = result[0].total_users
            const totalCommands = result[0].total_commands
            const totalLiveInfections = result[0].total_live_infections
            const totalLiveInfectedChannels = result[0].total_live_infected_channels
            const data = {
                totalInfections: totalInfections,
                totalUsers: totalUsers,
                totalCommands: totalCommands,
                totalLiveInfections: totalLiveInfections,
                totalLiveInfectedChannels: totalLiveInfectedChannels
            }
            console.log(data)
            return data
        });
    });
});
<body>
    <input type="text" id="fName" placeholder="First Name">
    <input type="text" id="lName" placeholder="Last Name">
    <button onClick="addName()"> Add Name </button>
    <script>
        function addName() {
            var fullName = firebase.functions().httpsCallable('fullName');
            //For the fullName we have defined that fullName takes some data as a parameter 
            fullName({}).then((result) => {
                console.log(result);
            }).catch((error) => {
                console.log(error);
            })
        }
    </script>
</body>
1 Answers

There are asynchronous calls in your code, one to open the connection to Mongo, and then another one to load the data from Mongo. By the time the daa has loaded and your return data executes, the close } of your Function has long since executed - and nobody will ever see that return.

In most cases, you can bubble up the promise that you'd typically get back from the API you call when starting an asynchronous operation. But it seems that MongoClient.connect doesn't return a promise, so you'll have to constructor you own like this:

exports.fullName = functions.https.onCall((lol, lol1) => {
  return new Promise((resolve, reject) => {  //  return a promise, so Cloud Functions knows to wait
    var MongoClient = require('mongodb').MongoClient;
    var url = "mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false";
    MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo = db.db("discord_pandemic");
        dbo.collection("ArrayStats").find().toArray(function(err, result) {
            if (err) throw err;
            const totalInfections = result[0].total_infections
            const totalUsers = result[0].total_users
            const totalCommands = result[0].total_commands
            const totalLiveInfections = result[0].total_live_infections
            const totalLiveInfectedChannels = result[0].total_live_infected_channels
            const data = {
                totalInfections: totalInfections,
                totalUsers: totalUsers,
                totalCommands: totalCommands,
                totalLiveInfections: totalLiveInfections,
                totalLiveInfectedChannels: totalLiveInfectedChannels
            }
            console.log(data)
            resolve(data); //  resolve the promise with the data for the user
        });
    });
  });
});

Since you're new to this asynchronous behavior, I highly recommend checking out:

Related