Node.js: Bad Request when exporting Google Doc with REST API - node.js

I'm trying to export multiple Google Docs from a folder with the Drive REST Api. In the following code, 'fileId' is set to a specific fileId (and it works perfectly!):
var service = google.drive('v3');
fileId = <file_id>
dest = <local_file>
service.files.export({
fileId: fileId,
mimeType: 'text/plain',
auth: <auth>
})
.pipe(dest);
However, when I nest this in a loop in order to export multiple files like so:
var service = google.drive('v3');
fileId = <file_id>
dest = <local_file>
service.files.list({
auth: <auth>,
pageSize: 1,
fields: "nextPageToken, files(id)"
}, function(err, resp) {
if (err) { return err; }
var files = resp.files
for (var file of files) {
var fileId = file.id;
service.files.export({
fileId: fileId,
mimeType: 'text/plain',
auth: auth
})
.pipe(dest);
}
});
I'm given the following error:
{ [Error: Bad Request]
code: 400,
errors:
[ { domain: 'global',
reason: 'badRequest',
message: 'Bad Request' } ] }
And for the life of me I can't figure out why. Any help is much appreciated, Thanks!

Related

Google Drive API uploading files

I'm trying to figure the google drive api (node.js) out for a client. I need to upload files to their drive. I've decided to use a service account and have the auth working. I'm trying to upload a sample file but I can't find it in my drive. My guess is I need to somehow link it to my drive, but I'm not sure. Here is the code I have based off of an example I found online:
async function upload(){
const drive = google.drive({
version: 'v3',
auth: authorize()
});
const res = await drive.files.create({
requestBody: {
name: 'Test',
mimeType: 'text/plain'
},
media: {
mimeType: 'text/plain',
body: 'Hello World'
}
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file.id);
}
});
authorize() returns the jwtclient and works fine.
console.log(res) returns file id undefined.
any help would be much appreciated!
When the response value is retrieved from googleapis for Node.js, please modify your script as follows.
From:
console.log('File Id: ', file.id);
To:
console.log('File Id: ', file.data.id);
Note:
In your script, I think that you can also use the following script.
const res = await drive.files
.create({
requestBody: {
name: "Test",
mimeType: "text/plain",
},
media: {
mimeType: "text/plain",
body: "Hello World",
}
})
.catch(console.log);
if (res) console.log("File Id: ", res.data.id);
Reference:
googleapis for Node.js

google drive api upload file after created new folder

I'm currently following Google Drive APIs document and trying to create function create a folder then upload a file to it after creation. Currently it only managed to create new folder but the file i want to upload to it doesn't appear in that newly created folder.
I already enable to the api and shared the target folder with the service account
upload.js
const { google } = require('googleapis');
const fs = require('fs');
const key = require('./test-creds.json');
const drive = google.drive('v3');
const targetFolderId = "1Q_2I3_UpAGs13jEMXGYLgm0dXahnhN4Z"
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/drive'],
null
);
function uploadFile(childFolderID) {
const fileMetadata = {
name: 'photo.jpg'
}
const media = {
mimeType: 'image/jpeg',
body: fs.createReadStream('photo.jpg'),
parents: [childFolderID]
}
drive.files.create({
auth: jwtClient,
resource: fileMetadata,
media: media,
fields: 'id'
}, (err, file) => {
if (err) {
console.log(err);
return;
} else {
console.log("imaged uploaded with id ", file.data.id);
console.log(childFolderID);
}
});
}
jwtClient.authorize((authErr) => {
if (authErr) {
console.log(authErr);
return;
}
const folderMetadata = {
name: 'child5',
mimeType: 'application/vnd.google-apps.folder',
parents: [targetFolderId]
};
drive.files.create({
auth: jwtClient,
resource: folderMetadata,
fields: 'id'
}, (err, file) => {
if (err) {
console.log(err);
return;
}
console.log('uploaded folder with id: ', file.data.id);
const childFolderID = file.data.id;
return uploadFile(childFolderID);
})
});
here the output:
uploaded folder with id: 1RKu9fxBr-6Pl7F0x5vfrqWb3cgH095BO imaged
uploaded with id 1QGBjXdv6GkgFQDtEsapA_hpAkXGRYEs7
any help would be appreciate :)
i found out what i did wrong the
parents: [childFolderID]
should be in fileMetadata because it's a file type so in fileUpload function it should be this:
const fileMetadata = {
name: 'photo.jpg',
parents: [childFolderID]
}
const media = {
mimeType: 'image/jpeg',
body: fs.createReadStream('photo.jpg'),
}

Google Drive v3. Nodejs Resumable Upload creates untitled file in wrong directory

Hey I have followed the steps from the Drive quick start guides and generated a token.json using the following scopes:
const SCOPES = [
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive.file'
];
I am then running the following code to try and create/upload a file to google drive.
async function testing() {
let driveFolder = 'FOLDERID';
let res;
try {
const oauth2Client = new google.auth.OAuth2(
credentials.client_id,
credentials.client_secret,
credentials.redirect_uris
);
await oauth2Client.setCredentials({
...tokenInfo
});
console.log('=== completed drive authentication', oauth2Client);
const drive = await google.drive({
version: 'v3',
auth: await oauth2Client
});
console.log('=== Initialised Drive API');
res = await drive.files.create({
parameters :{
uploadType: 'resumable'
},
requestBody: {
name: 'Testing.txt',
mimeType: 'text/plain',
parents: [driveFolder]
},
media: {
mimeType: 'text/plain',
body: 'Hello world!!!'
}
});
console.log('=== Completed Report UPLOAD:', res);
return;
} catch (err) {
console.error('ERROR: \n', err);
}
}
The request completes without catching an error but the response that returns is undefined.
The last two logs show the following
=== completed drive authentication OAuth2Client {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
transporter: DefaultTransporter {},
credentials:
{ access_token:
'ACCESS TOKEN STRING',
refresh_token:
'REFRESH TOKEN STRING',
scope:
'https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata',
token_type: 'Bearer',
expiry_date: 1551070810157 },
certificateCache: null,
certificateExpiry: null,
refreshTokenPromises: Map {},
_clientId:'CLIENT ID STRING VALUE',
_clientSecret: 'CLIENT SECRET VALUE',
redirectUri: [ 'REDIRECT URL', 'http://localhost' ],
authBaseUrl: undefined,
tokenUrl: undefined,
eagerRefreshThresholdMillis: 300000 }
=== Initialised Drive API
=== Completed Report UPLOAD: undefined
You can try the quickstart using NodeJS from the documentation:
// change the scopes
const SCOPES = [ 'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive.file'];
function uploadFile(auth){
var drive = google.drive('v3');
var fileMetadata = {
'name': 'Some.jpg' // name of the file
};
var media = {
mimeType: 'image/jpeg',
resumable: true,
//PATH OF THE FILE FROM YOUR COMPUTER
body: fs.createReadStream('/usr/local/google/home/malicdemj/Desktop/blue-cyber-future-technology-concept-background_42077-488.jpg')
};
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.data.id);
}
});
}
Uploaded file in my drive:
Also, please check this SO post for more details.

How to get progress status while uploading files to Google Drive using NodeJs?

Im trying to get progress status values while uploading files to google Drive using nodeJs.
controller.js
exports.post = (req, res) => {
//file content is stored in req as a stream
// 1qP5tGUFibPNaOxPpMbCQNbVzrDdAgBD is the folder ID (in google drive)
googleDrive.makeFile("file.txt","1qP5tGUFibPNaOxPpMbCQNbVzrDdAgBD",req);
};
googleDrive.js
...
makeFile: function (fileName, root,req) {
var fileMetadata = {
'name': fileName,
'mimeType': 'text/plain',
'parents': [root]
};
var media = {
mimeType: 'text/plain',
body: req
};
var r = drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: 'id'
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
// r => undefined
console.log("Uploaded: " + r);
}
});
},
...
i followed this link but got always an undefined value
How about this modification?
Modification point:
It used onUploadProgress.
Modified script:
makeFile: function (fileName, root,req) {
var fileMetadata = {
'name': fileName,
'mimeType': 'text/plain',
'parents': [root]
};
var media = {
mimeType: 'text/plain',
body: req
};
var r = drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: 'id'
}, {
onUploadProgress: function(e) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(e.bytesRead.toString());
},
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log("Uploaded: " + file.data.id);
}
});
},
Note:
If you want to show the progression as "%", please use the file size.
It was confirmed that this script worked at googleapis#33.0.0.
References:
axios
test of google/google-api-nodejs-client
In my environment, I'm using the script like above. But if this didn't work in your environment and if I misunderstand your question, I'm sorry.

Google Drive file.update with 2 legged oauth returns ok but doesn't work as expected

I have a service account made in console.developers.google.com and I've added the client ID of said service into admin.google.com for my domain wide delegation under Advanced settings > Authentication > Manage OAuth client access.
Using the Google Nodejs api client and Google Nodejs auth library, I have then created a jwt client using:
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
[
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive.scripts',
'https://www.googleapis.com/auth/drive.metadata'
],
'user#domain.com'
);
and with
const google = require('googleapis');
const sheets = google.sheets('v4');
const drive = google.drive('v3');
I've run
async.waterfall(
[
(callback) => {
sheets.spreadsheets.create(
{
auth: jwtClient,
resource: {
properties: {
title: 'Testing'
}
}
},
(err, spreadsheet) => {
console.log(spreadsheet);
callback(err, spreadsheet.spreadsheetId)
}
)
},
(spreadsheetId, callback) => {
drive.files.update(
{
auth: jwtClient,
fileId: spreadsheetId,
resource: {
addParents: config.folder
}
},
(err, file) => {
console.log(file);
callback(err, file);
}
)
}
],
(err, results) => {
if (err) {
console.log(err);
res.status(400).send({ error: err.toString() });
} else {
res.status(200).send("It lives!");
}
}
);
My response from the second call for file.update returns 200 and a response of the file:
{ kind: 'drive#file',
id: '<id-here>',
name: 'Testing',
mimeType: 'application/vnd.google-apps.spreadsheet' }
But strangely... the addParents are not reflected in the details of the file on the Drive webapp.
Any ideas. I'm in contact with Google apis support and haven't gotten anywhere in about a week. Many thanks in advance for your help!
The problem is that addParents is a query parameter, not a field in the Files resource. As such, it should be specified as a peer of fileId:
drive.files.update(
{
auth: jwtClient,
fileId: spreadsheetId,
addParents: config.folder
},
...

Resources