How to upload a file in a folder GOOGLE DRIVE API - node.js

So i try this, i use my folder ID, but that's doesn't work, my files are create but they don't go in my folder. In the doc of Google Drive there is only this example. When i submit a form on Slack, that's push my data on a Google Spreadsheet and after that's auto generate a ticket on monday. Now i want to push my spreadsheet on a special folder in my Drive.. Can i provide my files in an other way ?
async function createSpreadsheet(filename, body) {
const ID_FOLDER_DRIVE = MY_ID;
try {
const fileMetaData = {
'name': filename,
parents: [ID_FOLDER_DRIVE]
}
const media = {
mimeType: 'text/csv',
body: body
}
const res = await drive.files.create({
requestBody: {
resource: fileMetaData,
mimeType: 'application/vnd.google-apps.spreadsheet'
},
media: media
})
return res.data
} catch (error) {
throw error
}
}
async function generatePublicUrl(id) {
console.log({ id })
try {
await drive.permissions.create({
fileId: id,
requestBody: {
role: 'reader',
type: 'anyone',
},
});
/*
webViewLink: View the file in browser
webContentLink: Direct download link
*/
const result = await drive.files.get({
fileId: id,
fields: 'webViewLink, webContentLink',
});
return result.data.webViewLink
} catch (error) {
throw error
}
}

In your situation, how about the following modification?
From:
const fileMetaData = {
'name': filename,
parents: [ID_FOLDER_DRIVE]
}
const media = {
mimeType: 'text/csv',
body: body
}
const res = await drive.files.create({
requestBody: {
resource: fileMetaData,
mimeType: 'application/vnd.google-apps.spreadsheet'
},
media: media
})
To:
const fileMetaData = {
name: filename,
parents: [ID_FOLDER_DRIVE],
mimeType: 'application/vnd.google-apps.spreadsheet'
}
const media = {
mimeType: 'text/csv',
body: body
}
const res = await drive.files.create({
requestBody: fileMetaData,
media: media
})
Reference:
google-api-nodejs-client

Related

How export sheets to pdf and upload it in one specific folder?

I'm trying to convert one google sheet into a pdf file. Actually, that, seems ok. But i can't put it directly in one specifics folder ...
Can you help me ?
const getData = await getSpreadSheetData(newSpreadsheetsId);
if (!getData) {
// nop
return;
}
let url = getData.data.spreadsheetUrl;
if (!url) {
// nop
return
}
url = url.replace(/edit$/, '');
const url_ext = 'export?exportFormat=pdf&format=pdf&portrait=true'
url = url + url_ext;
const dest = fs.createWriteStream('test.pdf');
await g.drive.files.export(
{
fileId: `${newSpreadsheetsId}`, // Please set the file ID of Google Docs.
mimeType: "application/pdf"
},
{ responseType: "stream" },function(err, response) {
if (err) {
console.log(err);
return;
}
if (!response) {
// nop
return
}
response.data
.on("end", function() {
console.log("Done.");
})
.on("error", function(err) {
console.log("Error during download", err);
return process.exit();
})
.pipe(dest);
})
getSpreadSheetData retrieve me all the data from one spreadsheetID
I'm not an expert with pipe etc ...
I have trying some options like this link :
Github - google Drive export pdf in Landscape
And i don't want this file on my server, or transiting by my server ... :/
after few hours there is the solution :
g = auth
const exportAsPdfInFolder = await g.drive.files.export(
{
fileId: fileId,
mimeType: 'application/pdf',
alt: 'media',
},
{ responseType: 'stream' },
async (err, result) => {
if (err) console.log(err);
else {
const media = {
mimeType: 'application/pdf',
body: result?.data,
};
await g.drive.files.create(
{
requestBody: {
name: newTitlePDF,
parents: [folderParentId],
},
media: media,
fields: 'id',
},
async (err: any, file: any) => {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file.data.id);
}
},
);
}
},
);
Reference:
Files: create

Send image to Google Drive API from NodeJS

I managed to upload text files to google API with this code
google.drive({
version: 'v3',
auth
})
var media = {
mimeType: 'text/plain',
body: 'text'
}
drive.files.create({
media: media,
fields: 'id'
})
But if i try to upload an image as suggested in documentation i'm getting empty file on the drive.
Trying to do that this way (file exists and has all privileges)
const drive = google.drive({
version: 'v3',
auth
})
var media = {
mimeType: 'image/png',
body: fs.createReadStream(path.resolve(__dirname, '../assets/logo.png'))
}
drive.files.create({
media: media,
fields: 'id'
})
And when I overviewing request in debug console i see that there was no request body.
Please, help.
Below is the whole component which is doing the upload
<template>
<div>
<button class="btn btn-block btn-success mb-3" #click="connect">Syncronize</button>
<h3 class="text-center">
<template v-if="getToken">Sync success</template>
<template v-else>Sync failed</template>
</h3>
<button #click="tryUpload">Test API</button>
</div>
</template>
<script>
import OAuth2 from '../classes/OAuth2'
import { mapActions, mapGetters } from 'vuex'
const {google} = require('googleapis')
export default {
computed: {
...mapGetters([
'getToken'
])
},
methods: {
...mapActions([
'saveToken'
]),
connect () {
(async () => {
let token = await new OAuth2().getToken()
this.saveToken(token)
})()
},
tryUpload () {
const auth = new google.auth.OAuth2(
'....',
'.....',
'http://127.0.0.1:42813/callback'
)
auth.setCredentials(this.getToken)
const drive = google.drive({
version: 'v3',
auth
})
let stream = fs.createReadStream(path.resolve(__dirname, '../assets/logo.png'))
var media = {
mimeType: 'image/png',
body: stream
}
drive.files.create({
media: media,
fields: 'id'
}, function (err, file) {
if (err) {
console.error(err)
} else {
console.log('File Id: ', file.id)
}
})
}
}
}
</script>
Try importing the file with require instead
var media = {
mimeType: 'image/png',
body: require(path.resolve(__dirname, '../assets/logo.png'))
}
As it is, you are uploading the stream itself, not the file being streamed. If you want to use fs, you should try accessing the stream using the callback inside of the stream.on('{event}' function () {}) method.
It's working for me when I upload a file using arrow functions syntax and async/await (at least for me it's more comfortable like this):
// Your tryUpload Function
const tryUpload = async () => {
// ...Previous OAuth workflow
// Build Drive service
const drive = google.drive({version: 'v3', auth});
try {
const data = await uploadFile(drive);
console.log(data);
} catch(err){
console.log(`There was a problem in the promise ---> ${err}`);
}
}
const uploadFile = (drive) =>{
// Set file metadata and data
const fileMetadata = {'name': 'testupload.png'};
const media = {
mimeType: 'image/png',
// If it's in the same dir, just pass 'testupload.png'
body: fs.createReadStream('path/to/testupload.png')
};
// Return the Promise result after completing its task
return new Promise((resolve, reject) => {
// Call Files: create endpoint
return drive.files.create({
resource: fileMetadata,
media: media
},(err, results) => err ? reject(err) : resolve(results))
});
};
Docs
As a guide to help you. I used these docs:
Files: create.
Perform a simple upload.

Get readable stream from drive.files.get

I am writing a nodejs function to transfer files from google drive to some other place
Following is the sample code block to get file from drive
var fileId = '0BwwA4oUTeiV1UVNwOHItT0xfa2M';
var dest = fs.createWriteStream('/tmp/photo.jpg');
drive.files.get({
fileId: fileId,
alt: 'media'
})
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(dest);
instead of piping it to writable stream , I would like to get a readable stream that i can pass on to my function
uploadsomeplace(readableStream)
Update 1
i wrote a function to get that readable stream and upload it again to some folder in google drive (seems dumb but for test as drive.files.creates takes a readable stream)
const transferit = async () => {
var fileId = '0BwwA4oUTe1UVNwOHItT0xfa2M' // some valid id
let somereadstream = drive.files.get(
{ fileId, alt: 'media' },
{ responseType: 'stream' }
)
var folderId = '1oC90HZDLbfYiW2neSCMERHZ8ZH1X' // some valid id
var fileMetadata = {
name: 'photo.jpg',
parents: [folderId]
}
var media = {
mimeType: 'image/jpeg',
// body: fs.createReadStream('image.jpg')
body: somereadstream
}
return await drive.files.create({
resource: fileMetadata,
media: media
// fields: 'id'
})
}
transferit().then(data => console.log(data))
but i get error
(node:6200) UnhandledPromiseRejectionWarning: TypeError: part.body.pipe is not a function
drive.files.get returns a promise which if fulfilled gives a response object which contains the readable stream in response.data
const isStream = require('is-stream')
const transferit = async () => {
var fileId = '1uw5PhBF8z8uBsxmFKJef582Pp92UKpxM' // some valid id
let somereadstream = await drive.files.get(
{ fileId, alt: 'media' },
{ responseType: 'stream' }
)
console.log(somereadstream)
return isStream.readable(somereadstream.data)
}
By the looks of things
drive.files.get({
fileId: fileId,
alt: 'media'
})
already returns a readable stream. Just assign it to a variable and pass it into your function.
const readableStream = drive.files.get({
fileId: fileId,
alt: 'media'
});
uploadsomeplace(readableStream);
This works for me in typescript:
async function getReadableStreamForFileId(
drive: drive_v3.Drive,
fileId: FileId,
): Promise<stream.Readable> {
console.log('getReadableStreamForFileId', {drive, fileId});
// https://developers.google.com/drive/api/v3/manage-downloads#node.js
return (await drive.files.get(
{fileId, alt: 'media'},
{responseType: 'stream'},
)).data as any as Promise<stream.Readable>;
}
example:
const fileId = '1F2*******************xGC';
const fileDataStream = await getReadableStreamForFileId(drive, fileId);
const target = fs.createWriteStream('data-out');
fileDataStream.pipe(target);
drive is initialized as described in https://developers.google.com/drive/api/v3/quickstart/nodejs

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'),
}

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.

Resources