Node.jsでGoogle Driveにファイルをアップロードする (Google Drive API v3)


Google Driveへのファイルアップロードも試してみます。

* 参考記事
	* [Node.jsでGoogle Drive上のファイルを削除する (Google Drive API v3)](https://qiita.com/n0bisuke/items/a1b39635029242f31713)
	* [Node.jsでGoogle Drive上のファイルをリネームする (Google Drive API v3)](https://qiita.com/n0bisuke/items/dcc7be337a555b018b19)
	* [Node.jsでGoogle Drive上のファイルを指定フォルダに移動する (Google Drive API v3)](https://qiita.com/n0bisuke/items/8f108408a9e1067b9225)
	* [Node.jsでGoogle Drive上のファイルを複製（copy）する (Google Drive API v3)](https://qiita.com/n0bisuke/items/6d73bb6e1af123db9a9b)
	* [Node.jsでGoogle Driveの指定フォルダからファイル一覧を取得メモ (Google Drive API v3)](https://qiita.com/n0bisuke/items/ff1479cd14e7a0c0be0c)
	* [Node.jsでGoogle Drive上のファイルをダウンロードする (Google Drive API v3)](https://qiita.com/n0bisuke/items/61e037deb1926df5427c)

メソッドは[Files: create](https://developers.google.com/drive/api/v3/reference/files/create)になります。

ライブラリの書き方だと`drive.files.create()`です。

.uploadではないので注意。

## スコープ指定

```
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.appdata
```

## フォルダを指定してアップロード

[チュートリアル](https://developers.google.com/drive/api/v3/quickstart/nodejs)の`function listFiles`の箇所を書き換えて利用してみます。

> 機能的には`function createFile`とかにリネームした方が良いでしょうが一旦動かす体なのでスルー

`folderId`にGoogle Driveのアップロード先のフォルダのIDを指定しましょう。

パラメータでresource.parentsを指定していますが、ここが配列なので複数のフォルダに配置もできそうですね。

> 参考: [Create a file in a folder](https://developers.google.com/drive/api/v3/folder#create_a_file_in_a_folder)

また`test.mp4`としてますが、ファイルの種類によって拡張子は変えてください。

```create.js
//省略

async function listFiles(auth) {
    const drive = google.drive({version: 'v3', auth});

    const fileName = `test.mp4`;
    const folderId = 'xxxxx';

    const params = {
        resource: {
            name: fileName,
            parents: [folderId]
        },
        media: {
            mimeType: 'video/mp4',
            body: fs.createReadStream(fileName)
        },
        fields: 'id'
    };

    const res = await drive.files.create(params);
    console.log(res.data);
};
```

実行すると手元の`test.mp4`が指定したGoogle Driveのフォルダにアップロードされます。

> ![スクリーンショット 2020-08-26 2.22.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/3f7f83e7-7b9c-cfe4-fc8b-639a81475fd0.png "スクリーンショット 2020-08-26 2.22.53.png")

### おまけ: プログレス表示

[公式サンプル](https://github.com/googleapis/google-api-nodejs-client/blob/master/samples/drive/upload.js#L45-L50)を参考にして書くとこんな感じになります。

```dl.js
//省略

    const fileSize = fs.statSync(fileName).size;
    const res = await drive.files.create(params, {
        onUploadProgress: evt => {
          const progress = (evt.bytesRead / fileSize) * 100;
          readline.clearLine();
          readline.cursorTo(0);
          process.stdout.write(`${Math.round(progress)}% complete`);
        },
    });
    console.log(res.data);
```

* 実行

こんな感じのプログレス表示になります。

```bash
$ node create.js
・
・
・
mplete99% complete99% complete99% complete99% complete99% complete99% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete100% complete{ id: 'xxxxxxxxxxxxxx' }
```

## よもやま

`res.data`のあたりでなんとく分かる人はいるかもしれないですが、[こちら](https://github.com/googleapis/google-api-nodejs-client/blob/master/samples/drive/upload.js#L43)にコメントがあるようにaxiosを使ってアップロードしてるみたいですね。

そして[公式ドキュメント](https://developers.google.com/drive/api/v3/manage-uploads)がけっこうアップデートされていて公式のコード使えば良さそうってのに後から気づいた