Amine Gaaliche
Amine Gaaliche

Reputation: 93

Firebase callable function returning null result

The below google cloud function returns a null result.

Same code works fine with onRequest and returns data as expected. I want to use a callable function in order to easily send parameters to the function. Anybody knows what's wrong here?

const functions = require('firebase-functions');
const mysql = require('mysql');

exports.getUserData = functions.https.onCall((data, context) => {

const connectionName =
  process.env.INSTANCE_CONNECTION_NAME || 'instance';
const dbUser = process.env.SQL_USER || 'root';
const dbPassword = process.env.SQL_PASSWORD || 'password';
const dbName = process.env.SQL_NAME || 'someDb';

const mysqlConfig = {
  connectionLimit: 1,
  user: dbUser,
  password: dbPassword,
  database: dbName,
};
if (process.env.NODE_ENV === 'production') {
  mysqlConfig.socketPath = `/cloudsql/${connectionName}`;
}

let mysqlPool;

if (!mysqlPool) {
    mysqlPool = mysql.createPool(mysqlConfig);
}

mysqlPool.query('SELECT * from table where id = 1', (err, results) => {

if (err) {
  console.error(err);
} else {     
  data.send(JSON.stringify(results)); 
}

});
})

Upvotes: 1

Views: 838

Answers (2)

cmcc93
cmcc93

Reputation: 99

You can also wrap you mysqljs/mysql with a promise.

return new Promise((resolve, reject) => {

    if (!id) {
        resolve({success: false, customer: null, msg: 'No id provided.'});
    }

    let connection = mysql.createConnection({
        host: db.host,
        user: db.user,
        password: db.password,
        database: db.database
    });

    connection.connect(function (err) {
        
        if (err) {
            resolve({success: false, customer: null, msg: err});
        }

        let sql = "SELECT * FROM customers WHERE uid = ?);"
        let values = [id];

        connection.query(sql, values, function (error, result) {
            if (error) {
                console.log(error);
                return {success: false, customer: null, msg: error};
            } else {
                if (result.length) {
                    connection.destroy();
                    resolve({success: true, customer: customer});

                } else {
                    connection.destroy();
                    resolve({success: false, customer: null, msg: 'No customer details'});
                }

            }
            
        });
    });
});

Upvotes: 0

Renaud Tarnec
Renaud Tarnec

Reputation: 83048

As you will see in the three videos about "JavaScript Promises" from the official Firebase video series (https://firebase.google.com/docs/functions/video-series/) you MUST return a Promise or a value in your Cloud Function, to indicate to the platform that it has completed.

The mysqljs/mysql library you use does not return Promises, so one way is to use promise-mysql, which "is a wrapper for mysqljs/mysql that wraps function calls with Bluebird promises".

I've not tried it, but something along the following lines should do the trick:

const functions = require('firebase-functions');
const mysql = require('mysql');
const mysqlPromise =require('promise-mysql'); 

exports.getUserData = functions.https.onCall((data, context) => {

    //.....

    const connectionOptions = ...;

    return mysqlPromise.createPool(connectionOptions)   //you must return the Promises chain
    .then(pool => {
       return pool.query('SELECT * from table where id = 1')
    })
    .then(results => {
       return(results: JSON.stringify(results)); 
       //send back the response with return() not with data.send(), see the doc
    })
    .catch(error => {
        //See the Callable Functions doc: https://firebase.google.com/docs/functions/callable#handle_errors_on_the_client
    });

});

Upvotes: 5

Related Questions