google sheets api fails with missing parameter: spreadsheetId - node.js

I am trying to work with a google spreadsheet and the spreadsheet API. Following the directions, I have written the following:
const {google} = require('googleapis');
const auth = new google.auth.GoogleAuth({
keyFile: 'keys.json',
scopes: 'https://www.googleapis.com/auth/spreadsheets'
});
const authClientObject = auth.getClient();
const googleSheetInstance = google.sheets({version: 'v4',auth: authClientObject})
const spreadSheetId = 'customsheetid';
const result = googleSheetInstance.spreadsheets.values.get({
spreadSheetId,
range:'sheet1'
})
My problem is that it keeps failing. Any time I run this I get: UnhandledPromiseRejectionWarning: Error: Missing required parameters: spreadsheetId. Everything that I have read and looked at on both the official docs and StackOverflow, my get statement should be written correctly. But clearly, I am missing something and would appreciate any advice.

I needed to change the variable name. I took it from spreadSheetId to spreadsheetId.

Related

Google Calendar API and Service Account permission error

I'm trying to integrate the Google Calendar API in my app.
So far i've managed to do this:
Created a new project on Cloud Platform
Enabled Calendar API
Added a new service account with role: Owner
Generated jwt.json
Granted domain-wide for that service account
Shared a calendar with that service account (modify rights)
Enabled in the GSuite the option for everyone out of the organisation to modify the events
Now, my code on node.js looks like this:
const { JWT } = require('google-auth-library');
const client = new JWT(
keys.client_email,
null,
keys.private_key,
['https://www.googleapis.com/auth/calendar']
);
const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
const rest = await client.request({url});
console.log(rest);
The error I get is:
Sending 500 ("Server Error") response:
Error: Insufficient Permission
Anyone has any ideea? This gets frustrating.
How about this modification?
I think that in your script, the endpoint and/or scope might be not correct.
Pattern 1:
In this pattern, your endpoint of https://dns.googleapis.com/dns/v1/projects/${keys.project_id} is used.
Modified script:
const { JWT } = require("google-auth-library");
const keys = require("###"); // Please set the filename of credential file of the service account.
async function main() {
const calendarId = "ip15lduoirvpitbgc4ppm777ag#group.calendar.google.com";
const client = new JWT(keys.client_email, null, keys.private_key, [
'https://www.googleapis.com/auth/cloud-platform' // <--- Modified
]);
const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
const res = await client.request({ url });
console.log(res.data);
}
main().catch(console.error);
In this case, it is required to enable Cloud DNS API at API console. And it is required to pay. Please be careful with this.
I thought that the reason of your error message of Insufficient Permission might be this.
Pattern 2:
In this pattern, as a sample situation, the event list is retrieved from the calendar shared with the service account. If the calendar can be used with the service account, the event list is returned. By this, I think that you can confirm whether the script works.
Modified script:
const { JWT } = require("google-auth-library");
const keys = require("###"); // Please set the filename of credential file of the service account.
async function main() {
const calendarId = "###"; // Please set the calendar ID.
const client = new JWT(keys.client_email, null, keys.private_key, [
"https://www.googleapis.com/auth/calendar"
]);
const url = `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`; // <--- Modified
const res = await client.request({ url });
console.log(res.data);
}
main().catch(console.error);
Note:
This modified script supposes that you are using google-auth-library-nodejs of the latest version.
Reference:
JSON Web Tokens in google-auth-library-nodejs

Authentication Flow: How to use API

This flow is confusing me a bit and I would appreciate any help/diagram/flow-chart that could help me understand this better:
As an example, I would like to access Google's API. The thing is what I want to access sits on an enterprise account and to even get to use any of Google Suite Applications, I have to log in to my work account (SSO.) On top of that, all this needs to be done via VPN.
I've used Puppeteer for this in Node.js, and though it works on my machine, It stops working if I try to host it anywhere else because (I assume) due to the VPN issue. It's clunky and just plain hack-ish because I'm just automating what I normally do on the browser.
What are the best practices in being able to use Google's API? What does the algorithm look like?
you can use the 'googleapis' package on npm
https://www.npmjs.com/package/googleapis
here is an example...
const {google} = require('googleapis');
const bigquery = google.bigquery('v2');
async function main() {
// This method looks for the GCLOUD_PROJECT and GOOGLE_APPLICATION_CREDENTIALS
// environment variables.
const auth = new google.auth.GoogleAuth({
scopes: ['https://www.googleapis.com/auth/cloud-platform']
});
const authClient = await auth.getClient();
const projectId = await auth.getProjectId();
const request = {
projectId,
datasetId: '<YOUR_DATASET_ID>',
// This is a "request-level" option
auth: authClient
};
const res = await bigquery.datasets.delete(request);
console.log(res.data);
}
main().catch(console.error);
you can use a proxy by setting the process.env.http or process.env.httpsenvironment variables to solve your vpn issue

Deprecation of Google plus

I got a email from Google saying that the use of all Google+ APIs are being shut off. I currently use googleAPI.google.plus to sign people in using Google. Is this plugin going to add a update to support the new way of authorizing users with Google?
Environment details:
OS: Mac OS X
Node.js version: v 10.8.0
npm version: v6.5.0
googleapis version: 33
const googleAPI = require('googleapis');
const plus = googleAPI.google.plus({
version: 'v1',
auth: configs.googleAPIKey // specify your API key here
});
// Check if Google tokens are valid
plus.people.get({
userId: googleUserId,
fields: 'displayName,emails,name,image',
access_token: googleAccessToken
})
.then((user) => {
logger.debug('From google: ' + util.inspect(user.data));
logger.debug('First Name: ' + user.data.name.givenName);
logger.debug('Last Name: ' + user.data.name.familyName);
})
You don't show how you're using that object to do sign-in, so it is a little difficult to answer.
However, the googleapis package already supports sign-ins with an OAuth2 client that you can create with something like
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
You can then get a URL to redirect them to so they can sign-in with something like
const url = oauth2Client.generateAuthUrl({
// If you only need one scope you can pass it as a string
scope: scopes
});
and then redirect them to url. Once they have signed into that URL, they'll be redirected to the URL you have specified as YOUR_REDIRECT_URL which will include a parameter called code. You'll need this code to exchange it for credentials, including the auth token
const {tokens} = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens);
If you just need to use an API Key (which is what your example hints at), then you should just need to include the key the same way you do now for the API calls that you need to make. But that isn't related to authorization.
Since it looks like you want to get profile information, you can use something like userinfo or the People API and choose which fields you want for the user.
Using userinfo might look something like
oauth2client.userinfo.get().then( profile => {
// Handle profile info here
});
The people.get method gives you a little more control, and might look something like
const people = google.people({
version: "v1"
});
const fields = [
"names",
"emailAddresses",
"photos"
];
people.people.get({
resourceName: "people/me",
personFields: fields.join(',')
})
.then( user => {
// Handle the user results here
});

NodeJS: Google Sign-In for server-side apps

Following this documentation I succeed to perform Google Sign-In for server-side apps and have access to user's GoogleCalendar using Python on server side. I fail to do that with NodeJS.
Just in a nutshell - with Python I used the auth_code I've sent from the browser and got the credentials just like that:
from oauth2client import client
credentials = client.credentials_from_clientsecrets_and_code(
CLIENT_SECRET_FILE,
['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
auth_code)
Then I could store in DB the value of:
gc_credentials_json = credentials.to_json()
And generate credentials (yes it uses the refresh_token alone when it's needed):
client.Credentials.new_from_json(gc_credentials_json)
So I want to do the same using NodeJS:
easily generate credentials using just: CLIENT_SECRET_FILE, scopes and auth_code (just like I did with Python)
receive credentials using previous credentials value without analysing if the access token is expired - I prefer a ready (well tested by the community) solution
Thank you in advance!
I've implemented it using google-auth-library package.
Here is the function to retrieve the gcClient:
const performAuth = async () => {
const tokens = await parseTokenFromDB();
const auth = new OAuth2Client(
downloadedCredentialsJson.web.client_id,
downloadedCredentialsJson.web.client_secret
);
auth.on('tokens', async (newTokens) => {
updateDBWithNewTokens(newTokens);
});
await auth.setCredentials(tokens);
const gcClient = google.calendar({version: 'v3', auth});
return gcClient;
};
Here is the template for parseTokenFromCurrentDB function just to give the idea of its output:
const parseTokenFromCurrentDB = async () => {
// Put here your code to retrieve from DB the values below
return {
access_token,
token_type,
refresh_token,
expiry_date,
};
};
So using this implementation one can get gcClient:
const gcClient = await gc.getGcClient(org);
and use its methods, e.g.:
const gcInfo = await gc.getInfo(gcClient);
const events = await gc.getEvents(gcClient, calcPeriodInGcFormat());

Azure Node SDK - 500 response with filter option

I am seeing a weird error on the with Azure Node SDK where I get a 500 error back anytime i include anything in the filter attribute of the options parameter. I am using the Usage Details call within the ConsumptionManagementClient class. Code is below:
const credentials = await MsRest.loginWithServicePrincipalSecret(config.appId, config.apiKey, config.tenantId);
let client = new ConsumptionManagementClient(credentials, subscriptionId);
const scope = `/subscriptions/${subscriptionId}`;
const options = { filter: "usageStart ge datetime'2017-10-13T00:00:00.000Z'"};
let usage = await client.usageDetails.list(scope, options);
The above code produces a 500 error(even tried searching for other things another example being "billableQuantity ge 0.001") but it seems to error out no matter what i give it.
The code works fine when i try using another one of the options paramters:
const credentials = await MsRest.loginWithServicePrincipalSecret(config.appId, config.apiKey, config.tenantId);
let client = new ConsumptionManagementClient(credentials, subscriptionId);
const scope = `/subscriptions/${subscriptionId}`;
const options = { top: 50 };
let usage = await client.usageDetails.list(scope, options);
Any ideas? Thanks in advance for the help!

Resources