To create your NodeJS application connecting and writing to Google Sheets, you need to generate your authentication credentials.
- Go to Google Developer Console.
- Select or create a project.
- Navigate to the API libraries page here.
- Search for “Google Sheets API”, then click the “Enable” button to enable the Google Sheets API.
- Next, you need to generate OAuth client ID to use the API in code.
- Get one in your project’s credential page by clicking here. Go to the page -> Click “Create Credentials” -> “OAuth Client ID”
- It will open the “Create OAuth client ID” page, then choose the Other as we’re using this key in the node.js application.
- Finally, click on create. Now, your client ID and client secret will appear on a popup. Dismiss it.
- You should see a download button by now, click on it to download the credentials.
- Now, there will be a JSON file downloaded with credentials. Move the file to your project folder.
Install the required node packages by using the following command,
npm install google-auth-library –save
npm install googleapis –save
Here’s an example of Google authentication I’m using in one of my projects,
let fs = require('fs'); let readline = require('readline'); let { OAuth2Client } = require('google-auth-library'); let SCOPES = ['https://www.googleapis.com/auth/spreadsheets']; //you can add more scopes according to your permission need. But in case you chang the scope, make sure you deleted the ~/.credentials/sheets.googleapis.com-nodejs-quickstart.json file const TOKEN_DIR = __dirname + '/config/'; //the directory where we're going to save the token const TOKEN_PATH = TOKEN_DIR + 'token.json'; //the file which will contain the token class Authentication { authenticate(){ return new Promise((resolve, reject)=>{ let credentials = this.getClientSecret(); let authorizePromise = this.authorize(credentials); authorizePromise.then(resolve, reject); }); } getClientSecret(){ return require(TOKEN_DIR + '/credentials.json'); } authorize(credentials) { var clientSecret = credentials.installed.client_secret; var clientId = credentials.installed.client_id; var redirectUrl = credentials.installed.redirect_uris[0]; var oauth2Client = new OAuth2Client(clientId, clientSecret, redirectUrl); return new Promise((resolve, reject)=>{ // Check if we have previously stored a token. fs.readFile(TOKEN_PATH, (err, token) => { if (err) { this.getNewToken(oauth2Client).then((oauth2ClientNew)=>{ resolve(oauth2ClientNew); }, (err)=>{ reject(err); }); } else { oauth2Client.credentials = JSON.parse(token); resolve(oauth2Client); } }); }); } getNewToken(oauth2Client) { return new Promise((resolve, reject)=>{ var authUrl = oauth2Client.generateAuthUrl({ access_type: 'offline', scope: SCOPES }); console.log('Authorize this app by visiting this url: \n ', authUrl); var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('\n\nEnter the code from that page here: ', (code) => { rl.close(); oauth2Client.getToken(code, (err, token) => { if (err) { console.log('Error while trying to retrieve access token', err); reject(); } oauth2Client.credentials = token; this.storeToken(token); resolve(oauth2Client); }); }); }); } storeToken(token) { try { fs.mkdirSync(TOKEN_DIR); } catch (err) { if (err.code != 'EEXIST') { throw err; } } fs.writeFile(TOKEN_PATH, JSON.stringify(token)); console.log('Token stored to ' + TOKEN_PATH); } } module.exports = new Authentication();
Once the token is created, it will not ask again.
Update Google Sheet Asynchronously:
We need to authenticate every time before making a write operation to Google Sheet. So whenever a write operation is performed into a Google sheet, we need to go through an authentication step, so I’ve added an intermediate function doOperation().
const { google } = require("googleapis") const authentication = require("./authentication"); class Sheets { async authenticate() { const auth = await authentication.authenticate(); this.auth = auth; } async doOperation(spreadsheetId, range, data, operation) { await this.authenticate(); if(operation === 'write') { await this._writeToGoogleSheet(spreadsheetId, range, data); } } async _writeToGoogleSheet(spreadsheetId, range, data) { 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;
Here’s how to call it from an external node file,
const Sheets = require('sheets'); const dataToGoogleSheet = async function () { try { let spreadSheetId = '2ikWvEeWG7Pjbv_YJi5AMkjl14dFHMFcBfMfkEG65-p8'; //Google Sheet Id let range = 'Sheet1!A3:O'; //Sheet Name var activities = [ ['Work', 9], ['Eat', 2], ['Commute', 2], ['Play Game', 2], ['Sleep', 7] ]; let sheets = await new Sheets(); sheets.doOperation(spreadSheetId, range, activities, 'write'); } catch (error) { console.error(error); } }
By now, you should be able to write the data to the sheet. Let me know what you think about this approach in the comments.