Mathias
Mathias

Reputation: 83

Get contents of a specific file in google drive API with NodeJS

I have found many posts on how to retrieve the contents of a .txt file from the google drive with their API. I have tried using this:

const drive = google.drive({version: 'v3', auth});
    var data = drive.files.get({
        fileId: file_id,
        alt: "media"
    });
    data.execute(function(response){
        console.log(reponse)
    })

My error

data.execute(function(response){
     ^

TypeError: data.execute is not a function

and also data.then instead of data.execute each time there is an error that I research and find no resolution to it. Could someone please give me an updated version of how to get the contents of a file from the file id? As I think the previous answers are outdated somewhat.

Sorry if this is pretty obvious. I relatively new to javascript and apis in general. So this would help me out a lot as it's the final stretch before I finish my program :)

Thanks, Mathias

Upvotes: 2

Views: 6387

Answers (2)

Moebius
Moebius

Reputation: 6538

The solutions offered here do not handle concurrency correctly. The problem is that the functions will end before the stream of data for the file will end. Here is a solution where the function will end after the file data stream will be consumed:

import { google } from "googleapis"

const jwtClient = new google.auth.JWT("", undefined, "",
  ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive"]
)
const googleDrive = google.drive("v3")

async function downloadFile(fileId: string): Promise<Buffer> {
  await jwtClient.authorize()
  const res = await googleDrive.files.get(
    { fileId, alt: "media", auth: jwtClient },
    { responseType: "stream" }
  )

  const buffers: any[] = []
  await new Promise<void>((resolve, reject) => {
    res.data
      .on("end", () => {
        console.log(`End of reading the file`)
        resolve()
      })
      .on("error", err => {
        reject(`Cannot create file ${err}`)
      })
      .on("data", chunk => {
        buffers.push(chunk)
      })
  })

  console.log(`End of the function`)
  return Buffer.concat(buffers)
}

The message End of reading the file will be printed before the message End of the function will be printed.

Upvotes: 0

Apoorva Chikara
Apoorva Chikara

Reputation: 8783

When you run 'drive.files.get' for google drive API you receive a promise, and to get data you have to use then on it. This is how it works:

  const filePath = `give_path_tosave_file`;
  const dest = fs.createWriteStream(filePath);
  let progress = 0;

  drive.files.get(
    { fileId, alt: 'media' },
    { responseType: 'stream' }
  ).then(res => {
    res.data
      .on('end', () => {
        console.log('Done downloading file.');
      })  
      .on('error', err => {
        console.error('Error downloading file.');
      })  
      .on('data', d => {
        d+='';
        console.log(d);
        //data will be here
        // pipe it to write stream
        }   
      })  
      .pipe(dest);
  }); 

If above solution doesn't work, you can use this one. It is on official google website for doing the same:

var fileId = '1ZdR3L3qP4Bkq8noWLJHSr_iBau0DNT4Kli4SxNc2YEo';
var dest = fs.createWriteStream('/tmp/filename.txt');
drive.files.export({
  fileId: fileId,
  mimeType: 'application/txt'
})
    .on('end', function () {
      console.log('Done');
    })
    .on('error', function (err) {
      console.log('Error during download', err);
    })
    .pipe(dest);

For more info, you should check here.

Also, the below method will return all the files which you have access to in drive.

drive.files.list({}, (err, res) => {
  if (err) throw err;
  const files = res.data.files;
  if (files.length) {
  files.map((file) => {
    console.log(file);
  });
  } else {
    console.log('No files found');
  }
});

Upvotes: 3

Related Questions