Search code examples
javascriptclassjavascript-objects

Using asynchronous call in class javascript class constructor


I'm trying to create a class in Javascript basically to do all the google sheet functions. And before writing any function I'm calling the authenticate API in the constructor, but the authentication is not being completed before calling the actual function. Here's the code in the class file,

const { google } = require("googleapis")
const authentication = require("./authentication");

class Sheets {
    constructor() {
        this.test = 'stackoverflow';
        authentication.authenticate().then((auth)=>{
            this.auth = auth;
        });
    }

    async writeToSheet(spreadsheetId, range, data) {
        if(typeof spreadsheetId != "undefined") {
            console.log(this.test)
            console.log('Got the spreadsheetId:' + spreadsheetId)
            console.log('Got the auth:' + this.auth)
            return;    
        }

        var sheets = google.sheets('v4');
        await sheets.spreadsheets.values.update({
            auth: this.auth,
            spreadsheetId: spreadsheetId,
            range: range, //Change Sheet1 if your worksheet's name is something else
            valueInputOption: "USER_ENTERED",
            resource: {
                values: data
            }
        }, (err, response) => {
            if (err) {
            console.log('The API returned an error: ' + err);
            return;
            } else {
                console.log("Data updated to the sheet successfully!");
            }
        });
    } 
}

module.exports = Sheets;

And this is how I'm calling the function,

let sheets = await new Sheets();
sheets.writeToSheet(spreadSheetId, range, data);

When I'm calling the writeToSheet function as above, It's always printing the auth as undefined only like this,

stackoverflow
Got the spreadsheetId:9ijWvEeWG7Oybv_TJi5AMkjl18dFHMFcBfSfkEG24-p7
Got the auth:undefined

So, how to call the authenticate function before calling any other function in the class and set the this.auth synchronously? Any help on this would be greatly appreciated.


Solution

  • I think you just need to create an extra workflow type function that handles the authentication piece and then passes it to the logic you have for writeToSheet; something like this:

    const { google } = require("googleapis")
    const authentication = require("./authentication");
    
    class Sheets {
        async authenticate() {
            const auth = await authentication.authenticate();
            this.auth = auth;
        }
    
        async writeToSheet(spreadsheetId, range, data) {
            await this.authenticate();
            await _writeToSheet(spreadsheetId, range, data);
        } 
    
        async _writeToSheet(spreadsheetId, range, data){
            if(typeof spreadsheetId != "undefined") {
                console.log('Got the spreadsheetId:' + spreadsheetId)
                console.log('Got the auth:' + this.auth)
                return;    
            }
    
            var sheets = google.sheets('v4');
            await sheets.spreadsheets.values.update({
                auth: this.auth,
                spreadsheetId: spreadsheetId,
                range: range, //Change Sheet1 if your worksheet's name is something else
                valueInputOption: "USER_ENTERED",
                resource: {
                    values: data
                }
            }, (err, response) => {
                if (err) {
                console.log('The API returned an error: ' + err);
                return;
                } else {
                    console.log("Data updated to the sheet successfully!");
                }
            });
        }
    }
    
    module.exports = Sheets;
    

    This slightly alters your use of the function to the following:

    let sheets = new Sheets();
    await sheets.writeToSheet(spreadSheetId, range, data);
    

    You could add some of this into a constructor instead, but just be mindful that you are storing a class instance that was previously authenticated. It could present an issue if you store the instance and try to reuse it later with a now expired authentication token.