1

For hours I've been struggling with a problem involving Firebase Cloud Functions & Google Sheets API. I'm simply trying to read some cells in my spreadsheet upon a POST request to my Cloud Function.

The following code, where I read from the spreadsheet using a function readCells works just fine:

const {google} = require('googleapis');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();

// magic function (?)
function readCells(auth, ssheetId) {
    const sheets = google.sheets({version: 'v4', auth});
    return new Promise((resolve, reject) => {
        sheets.spreadsheets.values.get({spreadsheetId:ssheetId,
                                        range:'MySheet!A1:A2'},
                                        (err, result) => {
            if (err) {
                reject(err);
            }
            resolve(result);
        });
    });
}

exports.test = functions.https.onRequest((request, response) => {
    // read auth token & spreadsheet ID from Cloud Firestore        
    let tokenPromise = db.doc('config/token').get();
    let spreadsheetPromise = db.doc('config/spreadsheet').get();

    // read from spreadsheet
    return Promise.all([tokenPromise, spreadsheetPromise]).then(results => {
        const token = results[0].data();
        const ssheetId = results[1].data().id;
        const oAuth2Client = new google.auth.OAuth2(token.client_id, token.client_secret, "");
        oAuth2Client.setCredentials(token);
        return readCells(oAuth2Client, ssheetId);
    })
    .then(result => {
        console.log(result.data.values);
        return response.status(200).end();
    })
    .catch(err => {
        console.error(err);
        return response.status(500).end();
    });
});

Then I get rid of readCells and do everything in the HTTPS cloud function test:

exports.test = functions.https.onRequest((request, response) => {
    // read auth token & spreadsheet ID from Cloud Firestore
    let tokenPromise = db.doc('config/token').get();
    let spreadsheetPromise = db.doc('config/spreadsheet').get();

    // read from spreadsheet
    return Promise.all([tokenPromise, spreadsheetPromise]).then(results => {
        const token = results[0].data();
        const ssheetId = results[1].data().id;
        const oAuth2Client = new google.auth.OAuth2(token.client_id, token.client_secret, "");
        oAuth2Client.setCredentials(token);
        const sheets = google.sheets({version: 'v4', oAuth2Client});
        return new Promise((resolve, reject) => {
            sheets.spreadsheets.values.get({spreadsheetId:ssheetId,
                                            range:'MySheet!A1:A2'},
                                            (err, result) => {
                if (err) {
                    reject(err);
                }
                resolve(result);
            });
        });
    })
    .then(result => {
        console.log(result.data.values);
        return response.status(200).end();
    })
    .catch(err => {
        console.error(err);
        return response.status(500).end();
    });
});

But I get the following error:

error: { Error: The request is missing a valid API key.
    at createError (/<path_to_functions>/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/<path_to_functions>/node_modules/axios/lib/core/settle.js:18:12)
    at IncomingMessage.handleStreamEnd (/<path_to_functions>/node_modules/axios/lib/adapters/http.js:201:11)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
    ...
    more stuff
    ...

And also:

error: (node:3308) UnhandledPromiseRejectionWarning: 
Unhandled promise rejection. This error originated either by throwing
inside of an async function without a catch block,
or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:3308) [DEP0018] DeprecationWarning: Unhandled promise rejections
are deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with a non-zero exit code.

I don't understand this behaviour at all. I do the same thing only without using a function. I'm not very experienced in Javascript or Node.js; any help would be appreciated.

1 Answer 1

1

I managed to solve the problem by replacing the line

const sheets = google.sheets({version: 'v4', oAuth2Client});

with

const sheets = google.sheets('v4');

and passing the auth client directly to sheets.spreadsheets.values.get function.

So it became like this:

exports.test = functions.https.onRequest((request, response) => {
    let tokenPromise = db.doc('config/token').get();
    let spreadsheetPromise = db.doc('config/spreadsheet').get();
    return Promise.all([tokenPromise, spreadsheetPromise]).then(results => {
        const token = results[0].data();
        const ssheetId = results[1].data().id;
        const oAuth2Client = new google.auth.OAuth2(token.client_id, token.client_secret);
        oAuth2Client.setCredentials(token);
        const sheets = google.sheets('v4');
        return new Promise((resolve, reject) => {
            sheets.spreadsheets.values.get({spreadsheetId: ssheetId,
                                            auth: oAuth2Client,
                                            range: "MySheet!A1:A2"}, (err, result) => {
                if (err) {
                    reject(err);
                }
                resolve(result);
            });
        })
    })
    .then(result => {
        console.log(result.data.values[0][0]);
        return response.status(200).end();
    })
    .catch(err => {
        console.error(err);
        return response.status(500).end();
    });
});
Sign up to request clarification or add additional context in comments.

1 Comment

What kind of information is in the token variable? I'm having similar issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.