My wife and I use a shared google doc for our grocery list, and I often find myself forgetting to add groceries to our list which then results in us forgetting to buy things at the grocery store.
So I setup an automation when I tell google to add "something"
, IFTTT knows that when I say that, it sends a web request to my heroku server which then uses the google javascript api to update my google doc. I am happy with this setup and want to share with you all how I did it!
So this is Part 1 of a multi-part blog series on how to accomplish what I mentioned above! Stay tuned for the next parts!
Go to https://docs.new in your browser, and that will create a new google doc.
Title it Groceries (or whatever you want).
Note the id of the doc. It's between d/
and /edit
in the url.
Mine is 1OvhQtG2WYagqI-zBk_IXTRWhLijCu2_hB-ExdyCYI54
Creating oauth tokens with google nodejs apis
Run the following commands.
We'll be using yarn from here on out.
mkdir grocery-adder && cd grocery-adder
yarn init -y
git init
touch .gitignore
yarn add googleapis
mkdir src && touch src/index.js
Add the following to your .gitignore
file:
.idea
node_modules
Keep in mind that I will have credentials.json
and token.json
ignored in my final example so I don't compromise my google account to you all :)
For the rest of the oauth setup, I'm really just summarizing the following tutorial: https://developers.google.com/gmail/api/quickstart/nodejs
- Go to https://console.developers.google.com/apis/library/docs.googleapis.com
- Click
Enable
- Go to https://developers.google.com/gmail/api/quickstart/nodejs
- Click
Enable the Gmail API
- Save
credentials.json
togrocery-adder
- Paste the following code into
src/index.js
const fs = require("fs");
const readline = require("readline");
const { google } = require("googleapis");
// If modifying these scopes, delete token.json.
const SCOPES = ["https://www.googleapis.com/auth/documents"];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = "token.json";
// Load client secrets from a local file.
fs.readFile("credentials.json", (err, content) => {
if (err) return console.log("Error loading client secret file:", err);
// Authorize a client with credentials, then call the Gmail API.
authorize(JSON.parse(content), () => console.log("authorized!"));
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
* @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
* @param {getEventsCallback} callback The callback for the authorized client.
*/
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: SCOPES
});
console.log("Authorize this app by visiting this url:", authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Enter the code from that page here: ", code => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error("Error retrieving access token", err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), error => {
if (error) return console.error(error);
console.log("Token stored to", TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
- Run
node src/index.js
- Follow the prompts on the terminal
- You'll get a warning saying
This app isn't verified
, that's ok! You are the app!! - Great now you have
token.json
stored at the root ofgrocery-adder
- Run
node src/index.js
and you'll see thatauthorized!
is printed on the terminal - Now we can delete a lot of that setup code and write to your google doc!
Your file should look like the following:
const { google } = require("googleapis");
const token = require("../token.json");
const credentials = require("../credentials.json");
function authorize() {
const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
oAuth2Client.setCredentials(token);
return oAuth2Client;
}
async function main(YOUR_DOCUMENT_ID) {
const auth = await authorize();
const docs = google.docs({
version: "v1",
auth
});
await docs.documents.batchUpdate({
auth,
documentId: YOUR_DOCUMENT_ID,
requestBody: {
requests: [
{
insertText: {
location: {
index: 1
},
text: "hello!\n"
}
}
]
}
});
}
main("YOUR_DOCUMENT_ID");
If you see text: "hello!\n"
, you'll see what will be getting written to our doc!
Replace "YOUR_DOCUMENT_ID" with your document id and run it!
Now, if you go to your new google doc, you'll see hello!
printed there! If you keep running this, hello!
will continue getting added.
The code to generate the token can be found here
The code to write to the google doc can be found here
Top comments (3)
I'm getting the error "Hmmm… can't reach this page: localhost refused to connect. "
this occurs right after allowing the app to access my google account. (I never get the code nor token)
fixed it, the code was in the URL of the page between "code=" and "&scope"
This is awesome!
You saved me a lot of time with this!