Home > Blockchain >  Waiting for pool.query inside a callback in Express
Waiting for pool.query inside a callback in Express

Time:02-02

I'm using crypto.generateKeyPair inside a post endpoint in Express.

I need to insert the key generated inside my DB and then return within the endpoint the id row of the inserted row.

The endpoint code reads as:

app.post('/createKeys', (req, res) => {
crypto.generateKeyPair('rsa',,
   (err, publicKey, privateKey) => {
        if(!err) {
            let id = myfunction(publicKey.toString('hex'), 
                     privateKey.toString('hex'));

            console.log(id)
        } else {
            res.status(500).send(err);
        }
    });
});

async function myfunction(publicKey, privateKey) {
  await pool.query('INSERT INTO users (publickey, privatekey) VALUES ($1, $2) RETURNING id', 
    [publicKey, privateKey], 
    (error, results) => {
        if (error) {
          throw error;
        }
        resolve(results.rows[0]['id']);
  });
};

However, inside the callback in crypto I get only a Promise, or undefined if I don't use async/await. How can I await myfunction result so I can send back to the user the id?

CodePudding user response:

Several issues here:

await only does something useful when you are awaiting a promise.

pool.query() does not return a promise when you pass it a callback, so your await there is not doing anything useful.

resolve() is not a function that exists outside the context of creating a new promise with new Promise((resolve, reject) => { code here })

throw error inside an asynchronous callback will not do anything useful as there is no way to catch that exception and thus no way to implement any decent error handling. Don't write code that way. When you promisify the function (as shown below), you can then reject the promise and that will offer a way to propagate the error back to the caller.

Your choices for waiting for pool.query() with await here are:

  1. Use the version of your database that natively supports promises and then don't pass a callback to pool.query() so that it returns a promise that tells you when it's complete.

  2. Promisify your own function by wrapping pool.query() in a new promise and call resolve() and reject() appropriately.

Remember, do NOT mix plain callbacks and promise. Instead, promisify any asynchronous functions that use plain callbacks and then do all your logic flow with promises.

Here's a manually promisified version of your myfunction():

function myfunction(publicKey, privateKey) {
    return new Promise((resolve, reject) => {
        pool.query('INSERT INTO users (publickey, privatekey) VALUES ($1, $2) RETURNING id',
            [publicKey, privateKey],
            (error, results) => {
                if (error) {
                    reject(error);
                    return;
                }
                resolve(results.rows[0]['id']);
            });
    });
}

crypto.generateKeyPairP = util.promisify(crypto.generateKeyPair);


app.post('/createKeys', async (req, res) => {
    try {
        const {publicKey, privateKey } = await crypto.generateKeyPairP('rsa');
        const id = await myfunction(publicKey.toString('hex'), privateKey.toString('hex'));
        console.log(id);
        // send your response here, whatever you want it to be
        res.send(id);

    } catch(e) {
        res.status(500).send(e);
    }    
});

Note that in this implementation, the resolve and reject functions come from the new Promise() - they don't just exist in this air.

But, there is likely a version of your database or an interface in your existing database module where pool.query() can return a promise directly using built-in promise support.

  • Related