Skip to main content

Chapter 15 - Google Sheets (JavaScript)

Here's a JavaScript-flavoured version of the same concepts, using the official googleapis npm package to interact with Google Sheets.


Why Google Sheets + googleapis

  • Google Sheets has an official REST API; in JavaScript you use the googleapis package (maintained by Google) to access it.
  • Unlike Python's EZSheets wrapper, you work more directly with the Sheets API, but the concepts (auth, spreadsheets, sheets, cells) are the same.

Installing and setting up googleapis

Install the package:

npm install googleapis

One-time Google Cloud setup

Same 5 steps as Python:

  1. Create a Google Cloud project at https://console.cloud.google.com.
  2. Enable APIs — Google Sheets API and Google Drive API.
  3. Configure OAuth consent screen — External, add scopes for drive and spreadsheets, add test users.
  4. Create credentials — OAuth client ID → Desktop App → Download JSON → rename to credentials.json.
  5. Authorize — run your script, it opens a browser for consent, saves tokens for future use.

Example auth setup:

const { google } = require("googleapis");
const fs = require("fs");

const credentials = JSON.parse(fs.readFileSync("credentials.json", "utf-8"));
const { client_id, client_secret, redirect_uris } = credentials.installed;

const oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);

// After first-time auth flow, load saved token:
const token = JSON.parse(fs.readFileSync("token.json", "utf-8"));
oAuth2Client.setCredentials(token);

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

For simpler setups (server-to-server), use a service account instead of OAuth.


Spreadsheet objects

Creating a new spreadsheet

const res = await sheets.spreadsheets.create({
requestBody: { properties: { title: "My New Spreadsheet" } },
});
console.log(res.data.spreadsheetId);
console.log(res.data.spreadsheetUrl);

Opening an existing spreadsheet

const spreadsheetId = "1TzOJxhNKr15tzdZxTqtQ3EmDP6em_elnbtmZIcyu8vI";

const res = await sheets.spreadsheets.get({ spreadsheetId });
console.log(res.data.properties.title);
console.log(res.data.sheets.map((s) => s.properties.title));

Listing spreadsheets (via Drive API)

const drive = google.drive({ version: "v3", auth: oAuth2Client });

const res = await drive.files.list({
q: "mimeType='application/vnd.google-apps.spreadsheet'",
fields: "files(id, name)",
});
for (const file of res.data.files) {
console.log(file.id, file.name);
}

Downloading as Excel

const res = await drive.files.export(
{ fileId: spreadsheetId, mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
{ responseType: "arraybuffer" }
);
fs.writeFileSync("export.xlsx", Buffer.from(res.data));

Deleting spreadsheets

// Move to trash
await drive.files.update({ fileId: spreadsheetId, requestBody: { trashed: true } });

// Permanently delete
await drive.files.delete({ fileId: spreadsheetId });

Sheet objects

Creating and deleting sheets

// Add a new sheet
await sheets.spreadsheets.batchUpdate({
spreadsheetId,
requestBody: {
requests: [{ addSheet: { properties: { title: "Spam" } } }],
},
});

// Delete a sheet (need sheetId, not title)
await sheets.spreadsheets.batchUpdate({
spreadsheetId,
requestBody: {
requests: [{ deleteSheet: { sheetId: 0 } }],
},
});

Clearing a sheet

await sheets.spreadsheets.values.clear({
spreadsheetId,
range: "Sheet1",
});

Reading and writing cell data

Reading cells

const res = await sheets.spreadsheets.values.get({
spreadsheetId,
range: "Sheet1!A1:C2",
});
console.log(res.data.values);
// [['Name', 'Age', 'Favorite Movie'], ['Alice', '30', 'RoboCop']]

All values come back as strings (same as EZSheets).

Writing cells

await sheets.spreadsheets.values.update({
spreadsheetId,
range: "Sheet1!A1",
valueInputOption: "USER_ENTERED",
requestBody: {
values: [
["Name", "Age", "Favorite Movie"],
["Alice", 30, "RoboCop"],
],
},
});

valueInputOption: "USER_ENTERED" lets Google Sheets parse numbers and formulas; "RAW" stores everything as literal strings.


Reading and writing whole rows/columns

Get all rows

const res = await sheets.spreadsheets.values.get({
spreadsheetId,
range: "Sheet1", // entire sheet
});
const rows = res.data.values;
console.log(rows[0]); // header row
console.log(rows[1]); // first data row

Update a specific row

await sheets.spreadsheets.values.update({
spreadsheetId,
range: "Sheet1!A3:D3",
valueInputOption: "USER_ENTERED",
requestBody: { values: [["Pumpkin", "11.50", "20", "230"]] },
});

Append a row

await sheets.spreadsheets.values.append({
spreadsheetId,
range: "Sheet1",
valueInputOption: "USER_ENTERED",
requestBody: { values: [["NewItem", "5.00", "10", "50"]] },
});

Batch update all rows

await sheets.spreadsheets.values.update({
spreadsheetId,
range: "Sheet1!A1",
valueInputOption: "USER_ENTERED",
requestBody: { values: rows }, // 2D array of all rows
});

Google Forms

  • Same concept: Google Forms writes responses to a Sheets spreadsheet.
  • Your Node.js script reads that spreadsheet with the Sheets API and can automate responses (send notifications, trigger workflows, etc.).

Project: Fake Blockchain (Boringcoin)

Same toy "blockchain" concept: a spreadsheet with columns sender, recipient, amount.

Step 1: Audit balances

const { google } = require("googleapis");

// ... auth setup ...

const spreadsheetId = "BORINGCOIN_SPREADSHEET_ID";
const res = await sheets.spreadsheets.values.get({
spreadsheetId,
range: "Sheet1",
});

const accounts = {};

for (const row of res.data.values) {
const [sender, recipient, amountStr] = row;
const amount = parseInt(amountStr, 10);

if (sender === "PRE-MINE") {
accounts[recipient] = (accounts[recipient] ?? 0) + amount;
} else {
accounts[sender] = (accounts[sender] ?? 0) - amount;
accounts[recipient] = (accounts[recipient] ?? 0) + amount;
}
}

console.log(accounts);
const total = Object.values(accounts).reduce((sum, v) => sum + v, 0);
console.log("Total Boringcoins:", total);

Step 2: Add a transaction

const args = process.argv.slice(2);
if (args.length !== 3) {
console.log("Usage: node addTransaction.js SENDER RECIPIENT AMOUNT");
process.exit(1);
}

const [sender, recipient, amount] = args;

await sheets.spreadsheets.values.append({
spreadsheetId,
range: "Sheet1",
valueInputOption: "USER_ENTERED",
requestBody: { values: [[sender, recipient, amount]] },
});
console.log("Transaction added.");

values.append is cleaner than fetching all rows + re-uploading — it just adds to the end.


Overall idea of the chapter

Chapter 15 shows how to automate Google Sheets from JavaScript using the googleapis package: OAuth setup, creating/reading/writing spreadsheets, bulk row/column operations, and building projects on shared live data. The JS approach uses the Sheets API directly (no EZSheets wrapper), but the core patterns — auth once, read rows, write cells, append data — are the same.