Google-api-nodejs-client: Typescript wrong types on drive.files.get method return value

Created on 24 Jul 2019  路  4Comments  路  Source: googleapis/google-api-nodejs-client

Environment details

  • Node.js version: 10.xx
  • npm version: 6.xx
  • googleapis version: 41.0.1 (drive v3, JWT auth)

Steps to reproduce

  1. Take any accessible file id
  2. Set responseType: 'stream'

I am trying to download files (a JPG image in my case) from a GDrive with a service account. Authentication etc. works fine, but it seems there is an issue with the types when it comes to the drive.files.get method.

This request below is written in JavaScript and works fine, although the original google docs are not up to date this is the current workaround:

const dest = fs.createWriteStream('picture.jpg');
await drive.files.get(
    {
      fileId: '<file id here>',
      alt: 'media',
    },
    {
      responseType: 'stream',
    },
    (err, res) => {
      res.data
        .on('end', () => {
          console.log('Done');
        })
        .on('error', error => {
          console.log('Error during download', error);
        })
        .pipe(dest);
    }
  );

=> works fine, jpg is created and viewable


Using the same code working with Typescript:

const dest = fs.createWriteStream('photo.jpg');
await drive.files.get(
    {
      fileId: '<file id here>',
      alt: 'media',
    },
    {
      responseType: 'stream',
    },
    (err, res): void => {
      if (res) {
        res.data
          .on('end', (): void => { //Property 'on' does not exist on type 'Schema$File'. 
            console.log('Done');
          })
          .on('error', (error): void => {
            console.log('Error during download', error);
          })
          .pipe(dest);
      }
    }
  );

Receiving the following error:
Property 'on' does not exist on type 'Schema$File'.

res.data should be of type 'Stream' in this request configuration.


Finally I started to try&error around this issue and wanted to first wait for the Promise to finish and then write it to file without responseType: stream

  await drive.files
    .get({
      fileId: '<file id here>',
      alt: 'media',
    })
    .then((res): void => {
      console.log(typeof res.data); // string
      Buffer.from(res.data); // Argument of type 'Schema$File' is not assignable to parameter of type 'string'.
    });

At this point the only workaround for me is a crappy splitting of code into a JS module to fetch files and import the module in my TS code, because TS is all over the place with wrong types for the drive API.


And finally what does drive.files.get => res.data return? Is it a binary string? Is it something else? No explanation in the docs at all.

TypeScript p2 bug

Most helpful comment

Greetings folks! This ain't perfect, but I honestly don't know if it's something we can directly fix. The good news is that - you don't need to cast to any here - you can just cast to a stream:

const drive = google.drive({ version: "v3"});
const dest = fs.createWriteStream('picture.jpg');
const res = await drive.files.get({
  fileId: '<file id here>',
  alt: 'media',
}, {
  responseType: 'stream'
});
const streamy = res.data as Readable;
streamy.pipe(dest);

Does that cast work? The reason this is hard - I can't quite seem to get the return type to differ based on the specific values within an object. I will keep poking at it, but this should be a pretty simple work around.

All 4 comments

The problem is in the types here:

Return should always include Stream, ArrayBuffer, Blob alternative.
When sending request with alt:media option file contents are NOT received from type Schema$File

https://github.com/googleapis/google-api-nodejs-client/blob/master/src/apis/drive/v3.ts

   get(
      params?: Params$Resource$Files$Get,
      options?: MethodOptions
    ): GaxiosPromise<Schema$File>;
    get(
      params: Params$Resource$Files$Get,
      options: MethodOptions | BodyResponseCallback<Schema$File>,
      callback: BodyResponseCallback<Schema$File>
    ): void;
    get(
      params: Params$Resource$Files$Get,
      callback: BodyResponseCallback<Schema$File>
    ): void;
    get(callback: BodyResponseCallback<Schema$File>): void;
    get(
      paramsOrCallback?:
        | Params$Resource$Files$Get
        | BodyResponseCallback<Schema$File>,
      optionsOrCallback?: MethodOptions | BodyResponseCallback<Schema$File>,
      callback?: BodyResponseCallback<Schema$File>
    ): void | GaxiosPromise<Schema$File>

How to work with the file contents, since the docs do not provide any further details:

  • you MUST set the responseType: 'arraybuffer' | 'stream' | 'blob' to work with the binaries (default is JSON and you receive encoded JSON as file contents if you do not set anything)
  • if you use Typescript you have to overwrite the response type res:any

    const dest = fs.createWriteStream('p5.jpg');
    
    await drive.files.get(
    {
      fileId: '<file id>',
      alt: 'media',
    },
    {
      responseType: 'arraybuffer', // MUST set responseType (eg. Buffer)
    },
    (err, res: any): void => { // set res: any to overwrite the type
      if (res) {
        console.log(res.data); // arraybuffer
        dest.write(Buffer.from(res.data));
    }
    })
    

Greetings folks! This ain't perfect, but I honestly don't know if it's something we can directly fix. The good news is that - you don't need to cast to any here - you can just cast to a stream:

const drive = google.drive({ version: "v3"});
const dest = fs.createWriteStream('picture.jpg');
const res = await drive.files.get({
  fileId: '<file id here>',
  alt: 'media',
}, {
  responseType: 'stream'
});
const streamy = res.data as Readable;
streamy.pipe(dest);

Does that cast work? The reason this is hard - I can't quite seem to get the return type to differ based on the specific values within an object. I will keep poking at it, but this should be a pretty simple work around.

me salvou

Hey @JustinBeckwith. Just wanted to say great work with this lib!

I had a quick question. What would I cast to if I were specifying a responseType of 'blob'?

Was this page helpful?
0 / 5 - 0 ratings