google-api-nodejs-client: Failed to export a file using drive API

I am using:

  • googleapis@12.3.0
  • node@4.3.2

I was trying to download a spreadsheet using Drive API v3 like this:

drive.files.export({
    fileId: <some-valid-file-id>
    mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
}, (err, buf) => {
    if (err) {
        console.log('Error:', err);
        return;
    }

    console.log('Received %d bytes', buf.length);
    fs.writeFileSync('./out.xlsx', buf);
});

Resulting file was corrupted. Same situation with ‘application/pdf’ - I could not open them. After some investigation, I noticed that node-request module downloads data as string (decoded as utf8) by default unless you specify encoding option set to null. (what I am downloading here are binary files!)

// cited from - https://github.com/request/request
encoding - Encoding to be used on setEncoding of response data. If null, the body is returned as a Buffer. Anything else (including the default value of undefined) will be passed as the encoding parameter to toString() (meaning this is effectively utf8 by default). (Note: if you expect binary data, you should set encoding: null.)

By adding a line in drive.files.export() function like below, I was able to download the file successfully:

// ./apis/drive/v3.js
    export: function (params, callback) {
      var parameters = {
        options: {
          url: 'https://www.googleapis.com/drive/v3/files/{fileId}/export',
          method: 'GET',
          encoding: null // <===== added line
        },
        params: params,
        requiredParams: ['fileId', 'mimeType'],
        pathParams: ['fileId'],
        context: self
      };

I am aware this file is generated with swig, and probably other methods (like drive.files.get with “alt” set to “media” for binary data) are suffering from the same problem, I do not have sufficient knowledge to propose most effective solution to this. I hope some one could come up with a good idea to this problem.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 21 (9 by maintainers)

Commits related to this issue

Most upvoted comments

@enobufs I’m thinking #623 ought to be able to solve this for you (allow you to pass encoding: null).

@PMobile78 Thank you so much. That did work for me. Just in case somebody need it, Im leaving the code bellow to save the file.

` const jsonDownlaodFile = { fileId: fileId, // FILE IDENTIFIER mimeType: type ,// application/vnd.openxmlformats-officedocument.spreadsheetml.sheet }

    const jsonOptions = { 
        responseType: 'stream'
    }

    const res = await drive.files.export( jsonDownlaodFile, jsonOptions );
    //    └-> The result is an Object that contains a data attribute 
    //        this attribute is a PassThrough stream object, that ca be 
    //        saved in the local storage as shown bellow :
    let streamToSave = fs.createWriteStream(fileName);
    res.data.pipe(streamToSave) // The "data" object of "res" is the one that can be Piped

    
    streamToSave.on ('finish',function () { 
        console.log ("Proccess FInished"); 
        streamToSave.close(); 
    });
    streamToSave.on ('close', function () {
        console.log('Stream closed');
        const obj = xlsx_node.parse(fileName);
    });
    streamToSave.on ('error', function (error) { 
        console.log('ErrorStream:' , error) 
    });

`

Thank you again for the support.

@DavidIdentica You should use responseType: 'stream'. Look at https://github.com/googleapis/google-api-nodejs-client

const res = await drive.files.export({
  fileId: 'asxKJod9s79', // A Google Doc
  mimeType: 'application/pdf'
}, {
  // Make sure we get the binary data
  responseType: 'stream'
});