Basic file download example - node.js

I have been struggling my brain reading the nodejs documentation for google-apis.
I gathered a pretty long list of examples, but any of them helps me to do what I want to do. I just want to download a file from my drive using node js.
I have set up the OAUTH and I get an access token using this code (source: http://masashi-k.blogspot.com.es/2013/07/accessing-to-my-google-drive-from-nodejs.html )
var googleDrive = require('google-drive');
var GoogleTokenProvider = require("refresh-token").GoogleTokenProvider,
async = require('async'),
request = require('request'),
_accessToken;
var tokenProvider = new GoogleTokenProvider({
'refresh_token': REFRESH_TOKEN,
'client_id' : CLIENT_ID,
'client_secret': CLIENT_SECRET
});
tokenProvider.getToken(function(err, access_token) {
console.log("Access Token=", access_token);
_accessToken = access_token;
});
But I don't know how to continue from here. I tried with things like this with no luck:
function listFiles(token, callback) {
googleDrive(token).files().get(callback)
}
function callback(err, response, body) {
if (err) return console.log('err', err)
console.log('response', response)
console.log('body', JSON.parse(body))
}
listFiles(_accessToken,callback);
I feel like I'm very close, but I need some help here.
Thanks in advance.

There are two ways of doing that, depending on what you want to download. There is a big difference between downloading native Google Doc files and normal files:
Docs have to be downloaded using files.export API method, providing proper mime type to convert doc into
Normal files can be downloaded using files.get method, providing correct flag if you want to download file data instead of metadata
I'd suggest using GoogleApis NodeJS library (https://github.com/google/google-api-nodejs-client)
Initializing Drive API:
var Google = require('googleapis');
var OAuth2 = Google.auth.OAuth2;
var oauth2Client = new OAuth2('clientId','clientSecret','redirectUrl');
oauth2Client.setCredentials({
access_token: 'accessTokenHere'
refresh_token: 'refreshTokenHere'
});
var drive = Google.drive({
version: 'v3',
auth: this.oauth2Client
});
Importing file:
drive.files.get({
fileId: fileId,
alt: 'media' // THIS IS IMPORTANT PART! WITHOUT THIS YOU WOULD GET ONLY METADATA
}, function(err, result) {
console.log(result); // Binary file content here
});
Exporting native Google docs (you have to provide mime type for conversion):
drive.files.export({
fileId: fileId,
mimeType: 'application/pdf' // Provide mimetype of your liking from list of supported ones
}, function(err, result) {
console.log(result); // Binary file content here
});
Maybe it will help someone after so much time ;)

Take a look at the officially supported NodeJS client library for Google APIs at https://github.com/google/google-api-nodejs-client
The code required to get a file from Drive will be similar to that code at the bottom of the README used for inserting a file into Google Drive. You can also test your parameters to the API by using the API Explorer: https://developers.google.com/apis-explorer/#p/drive/v2/drive.files.get
Here's an example call to get a file from Google Drive:
client
.drive.files.get({ fileId: 'xxxx' })
.execute(function(err, file) {
// do something with file here
});

Related

Oauth2 with Google docs API Node.js (trying to programmatically write a new google doc)

I have a typical web app with a client and a node.js server. When a user selects an option on the client, I want to export (create) a google doc in their drive.
I am half way there following this tutorial https://developers.google.com/identity/protocols/oauth2/web-server
With my current set up, after the user authenticates, the authentication token is sent to a web hook (server side), but I don't have any of the data for creating the google doc there.
If I did, I could create the doc from there. Otherwise, I need to send the token itself back to the client so I can create the doc with the necessary payload from there.
In that case, I don't know how to signal to the client that the user has been authenticated. Should I use a web socket?
Something tells me that my general set up might not be correct, and that I should be doing it a different way in my use case.
This is my client side code that brings the user to the google auth page after getting the auth url (not sure if this really needs to be done server side, but since I have some user credentials I thought it might be better).
export async function exportToGoogleDoc() {
const response = await POST(`${API_URL}export/gdoc`, {
'hello': 'world'
});
if (response.status == 200){
window.location.href = response.authUrl;
}
}
And then the endpoint (just returns the autheticationUrl)
api.post('/export/gdoc', express.raw({ type: 'application/json' }), async (req, res, next) => {
try {
const scopes = [
'https://www.googleapis.com/auth/drive'
];
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
const authorizationUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true
});
res.json({ 'status': 200, authUrl : authorizationUrl } );
} catch (err){
next(err);
}
});
But then after the user agrees and authenticates with their google account, the auth token is sent to this web hook. At the bottom I am able to write an empty google doc to the authenticated google drive, but I don't have the data I need to create the real doc.
api.get('/auth/google', express.raw({ type: 'application/json' }), async (req, res, next) => {
const q = url.parse(req.url, true).query;
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
if (q.error) {
console.log('Error:' + q.error);
} else {
const { tokens } = await oauth2Client.getToken(q.code.toString());
oauth2Client.setCredentials(tokens);
const drive = google.drive('v3');
const requestBody = {
'name': 'Dabble',
'mimeType': 'application/vnd.google-apps.document',
};
drive.files.create({
requestBody: requestBody,
fields: 'id',
auth: oauth2Client
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file);
}
});
}
Somehow I either need to get the data for the google doc inside this web hook, or to listen for this web hook from the client.
OR I need an entirely different set up. I realize I also should be probably storing this token somewhere (local storage on client side?) and only making this call if they do not have a token.
Can anyone help me modify my set up? Thanks!

Error 'Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup' on API call

Trying to make my expressJS app control users' google drive files. I've been utilizing the node 'googleapis' package. After following a slightly dated/incorrect article here, I've gotten the script to:
redirect a user to their authorization url
grab the 'code' from get parameter and then...
register it back as access tokens, which can then be used to...
create a registered 'auth' object
When I use this to create the drive object and try to get it to list files, I get the following error: 'Error: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup'
This error has already popped up on SO question, and on github.
Following general advice, I re-enabled the drive api, re-downloaded access key. I've also tried replacing the sensitive drive scope a gmail scope, but that didn't work either. I'm not sure where else turn to start debugging at this point. I have a sneaking suspicion my entire auth object is being formed incorrectly but I can't find anything wrong.
This is the related piece of Express app code I'm using to create the authObject and then read drive files.
/**
* Google Utility class that packages different actions related to authentication
*/
class GoogleUtil {
constructor(secretFileName = 'client_secret.json') {
const secret = JSON.parse(fs.readFileSync(secretFileName)).web;
const { client_id, client_secret, redirect_uris } = secret;
this.client_id = client_id;
this.client_secret = client_secret;
this.redirect_uri = redirect_uris[0];
this.standardScope = [
'https://www.googleapis.com/auth/drive',
// 'https://www.googleapis.com/auth/gmail.readonly',
// 'https://www.googleapis.com/auth/userinfo.profile'
];
}
createConnection() {
return new google.auth.OAuth2(this.client_id, this.client_secret, this.redirect_uri); // form authObject
}
getConnectionUrl(auth) {
return auth.generateAuthUrl({
access_type: 'offline',
prompt: 'consent',
scope: this.standardScope
});
}
async getAccessTokenFromCode(code) {
var auth = this.createConnection();
const data = await auth.getToken(code);
return data.tokens;
}
}
const g = new GoogleUtil();
/**
* BEGIN ROUTE DEFINITIONS
*/
// THIS IS FIRST STEP. FRONTEND WILL REDIRECT TO GIVEN URL
app.get('/api/googleLoginUrl', async (req, res) => {
const oAuth2Client = g.createConnection();
const url = g.getConnectionUrl(oAuth2Client);
res.json({ url });
});
// *****
// NOTE: THIS IS ROUTE THAT ATTEMPTS TO LIST FILES AND THROWS ERROR
// *****
app.get('/google-auth-redirect', async (req, res) => {
if (!req.query.code) return res.send('Malformed request');
const tokens = await g.getAccessTokenFromCode(req.query.code);
const auth = g.createConnection().setCredentials(tokens);
const drive = google.drive({ version: 'v3', auth: auth });
drive.files.list({
pageSize: 10,
fields: 'nextPageToken, files(id, name)',
}, (err, resp) => {
if (err) return console.log('The API returned an error: ' + err);
console.log(resp);
});
res.redirect('/');
});
In the google developer console, clicking on 'create credentials' in the drive API overview informs me that my current credentials are compatible. The project scopes do include ' ../auth/drive'.
I'd want it to be able to list files from an authenticated user's account.
I think this might be related to how you are asking for permissions. If you are using your application to manipulate user's drive files you need a couple of things:
Check you have the correct access scopes setup.
Check you authentication parameter/Oauth screen is setup with said scopes.
You might want to read some documentation regarding authorizing users
Hope this helps! ;)

Upload file to google drive using REST API in Node.js

I am trying to upload a file to google drive using rest API(insert) in node.js, I have access_token and refresh_token. how can I upload without any sdk.
I was successful in testing this NodeJS upload by modifying the NodeJS basic upload sample a bit and mixing it with the already available NodeJS Quickstart
Here's the upload function:
function uploadFile(auth){
var drive = google.drive('v3');
var fileMetadata = {
'name': 'uploadImageTest.jpeg'
};
var media = {
mimeType: 'image/jpeg',
//PATH OF THE FILE FROM YOUR COMPUTER
body: fs.createReadStream('/usr/local/google/home/rrenacia/Downloads/noogui.jpeg')
};
drive.files.create({
auth: auth,
resource: fileMetadata,
media: media,
fields: 'id'
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file.id);
}
});
}
You can use the NodeJS Quickstart as reference for authorization. Change listFiles function name:
authorize(JSON.parse(content), listFiles);
to the name of your upload function, in this case:
authorize(JSON.parse(content), uploadFile);
A sucessful upload on my Google drive:
Check this out Node.js QuickStart for Google Drive

Node: Google Drive API for listing all files using query

May I know how can I list all the files using query in the Google Drive using the GoogleAPIS library
https://github.com/google/google-api-nodejs-client/
I have no idea, how to use this library!
I dont know where should I place my query, I have tried the code below, but I am not getting any response..
Test 1:
drive.files.list("mimeType='image/jpg'", function(data){
//I am getting all the data, the query is not working..
));
Test 2:
drive.files.list({
media: {
mimeType: 'application/vnd.google-apps.folder'
}
}, function(err, data){
//I am getting all the data, the query is not working..
});
Test 3:
drive.files.list({
resource: {
mimeType: 'application/vnd.google-apps.folder'
}
}, function(err, data){
//This returns error not working at all!
});
You can check the drive.files.list function given here https://github.com/google/google-api-nodejs-client/blob/master/apis/drive/v2.js#L733 and use something like the following for it.
var drive = google.drive({ version: 'v2', auth: oauth2Client });
drive.files.list({
q='mimeType='image/jpg''
}, callback);
More details on the input parameters for the list function are on https://developers.google.com/drive/v2/reference/files/list

Accessing google analytics through nodejs

I'm using nodejs, and I would like to display some data from google analytics.
On google API explorer, I've find this url to get my data:
https://www.googleapis.com/analytics/v3/data/ga?ids=ga%XXXXX&start-date=2013-08-17&end-date=2013-09-15&metrics=ga%3Avisits&key={YOUR_API_KEY}
However, if I access this url I get:
{"error":{"errors":[{"domain":"global","reason":"required","message":"Login Required","locationType":"header","location":"Authorization"}],"code":401,"message":"Login Required"}}
How can I pass my login through the url and then access my data ?
Thanks!
From the Google API console, you need to activate the Analytics API, and finally setup a Service Account, you'll then download a *.p12 file.
From this *.p12 file, you need to convert it to a *.pem file, to do that, run the following:
openssl pkcs12 -in XXXXX.p12 -nocerts -nodes -out XXXXX.pem
You'll be asked a password, it should be notasecret
Now you got the *.pem file you need, and the account email is the one displayed in the google api console, as EMAIL ADDRESS.
Don't forget to add this address to your analytics account (see: Analytics Google API Error 403: "User does not have any Google Analytics Account")
You should be good to go with the following snippet:
var googleapis = require('googleapis'),
JWT = googleapis.auth.JWT,
analytics = googleapis.analytics('v3');
var SERVICE_ACCOUNT_EMAIL = 'XXXXXXXXXX#developer.gserviceaccount.com';
var SERVICE_ACCOUNT_KEY_FILE = __dirname + '/key.pem';
var authClient = new JWT(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_KEY_FILE,
null,
['https://www.googleapis.com/auth/analytics.readonly']
);
authClient.authorize(function(err, tokens) {
if (err) {
console.log(err);
return;
}
analytics.data.ga.get({
auth: authClient,
'ids': 'ga:XXXXXXXX',
'start-date': '2015-01-19',
'end-date': '2015-01-19',
'metrics': 'ga:visits'
}, function(err, result) {
console.log(err);
console.log(result);
});
});
Are you setting Content-Type to application/x-www-form-urlencoded?
If you're still stuck, it's worth noting that Google has released a nodejs client library (alpha) here: https://github.com/google/google-api-nodejs-client
#xavier.seignard I follow your snippet but with modifications because I'm using a json file instead of p12 (code below).
But I have a doubt, I'm developing a restful backend in nodejs.
In this case, isn't it necessary to put the ga.get function inside the app.use() to obtain analytics information for every request that is made?
var key = require('filename.json');
var authClient = new JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/analytics.readonly']);
Below I have mentioned step by step process for Accessing google analytics through nodejs:
For more details : How To Use Google Analytics Reporting API With Nodejs
Install googleapis package
npm i googleapis
Import
const { google } = require('googleapis')
This is sample scripts for getting total views in last month:
const { google } = require("googleapis");
const scopes = "https://www.googleapis.com/auth/analytics.readonly";
const jwt = new google.auth.JWT(
process.env.CLIENT_EMAIL,
null,
process.env.PRIVATE_KEY.replace(/\\n/g, "\n"),
scopes
);
const view_id = "Your_View_ID";
async function getViews(){
try {
await jwt.authorize();
const response = await google.analytics("v3").data.ga.get({
auth: jwt,
ids: "ga:" + view_id,
"start-date": "30daysAgo",
"end-date": "today",
metrics: "ga:pageviews",
});
console.log(response);
} catch (err) {
console.log(err);
}
};`

Resources