Google Drive Apiでファイル取得する(Javascriptで)

# 概要

　[前回の投稿](http://qiita.com/comefigo/items/37e0e7668166d494b922)に引き続きGoogle Drive Apiを使用してファイルの取得についてのサンプルコードと使い方の説明です

# サンプルコード

以下ではAPIのV3のコードになりますが、V2のサンプルコードもリポジトリにありますので、利用される方はそちらも合わせて確認してください。

サンプルコードでは以下の機能が実装されています

- フォルダとファイルの一覧の取得
- フォルダをダブルクリックすると下位階層のファイルとファイルの取得
- 「次」ボタンでフォルダとファイルの追加取得
- ファイルのダウンロード
- ファイルのプレビュー


```html:google-drive-v3-sample.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <title>get google drive files sample</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://apis.google.com/js/client.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha256-/SIrNqv8h6QGKDuNoLGA4iret+kyesCkHGzVUUV0shc="
        crossorigin="anonymous"></script>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
        crossorigin="anonymous">
    <script>
        var googleDriveClient;
        var nextPageToken;
        var parentId;
        getGoogleAuth().then(loadGoogleDrive).then(function (gClient) {
            googleDriveClient = gClient;
            getFileList().then(function (objFileList) {
                viewFileList(objFileList);
            });
        });

        // load google drive client
        function loadGoogleDrive() {
            var p = new Promise(function (resolve, reject) {
                try {
                    window.gapi.client.load('drive', 'v3', fncOnDriveApiLoad);
                } catch (e) {
                    reject(e);
                }

                function fncOnDriveApiLoad() {
                    resolve(window.gapi.client);
                }
            });
            return p;
        }

        // authorize google
        function getGoogleAuth() {
            var objAuthParam = {
                'client_id': 'クライアントID',
                'scope': ['https://www.googleapis.com/auth/drive'],
                'immediate': false
            };
            var p = new Promise(function (resolve, reject) {
                window.gapi.load('auth', {
                    'callback': function () {
                        window.gapi.auth.authorize(
                            objAuthParam,
                            authResult);
                    }
                });

                function authResult(objAuthResult) {
                    if (objAuthResult && !objAuthResult.error) {
                        resolve(objAuthResult.access_token);
                    } else {
                        // auth failed.
                        reject(objAuthResult);
                    }
                }
            });
            return p;
        }

        // get drive file list
        function getFileList(strPageToken, strParentId) {
            var objParam = {
                pageSize: 10,
                orderBy: 'folder,modifiedTime',
                q: 'trashed=false',
                fields: 'files(id, name, kind, size, mimeType, lastModifyingUser, modifiedTime, iconLink, owners, folderColorRgb, shared, webViewLink, webContentLink), nextPageToken'
            };
            if (strParentId) {
                objParam.q += ' and ' + '"' + strParentId + '" in parents';
            }
            if (strPageToken) {
                objParam.pageToken = strPageToken;
            }
            var p = new Promise(function (resolve, reject) {
                var objReq = googleDriveClient.drive.files.list(objParam);
                objReq.execute(function (resp) {
                    resolve(resp);
                });
            });
            return p;
        }

        // ファイルの一覧表示
        function viewFileList(objFileList) {
            var arrayFiles = objFileList.files;
            nextPageToken = objFileList.nextPageToken ? objFileList.nextPageToken : '';
            for (var i = 0; i < arrayFiles.length; i++) {
                var file = arrayFiles[i];
                var filename = $('<td/>').text(file.name);
                var filesize = $('<td/>').text(file.size ? file.size : '-');
                var viewLink = file.webViewLink ? $('<a/>').attr('href', file.webViewLink).text('表示') : '<span/>';
                var fileview = $('<td/>').append(viewLink);
                var dlLink = file.webContentLink ? $('<a/>').attr('href', file.webContentLink).text('DL') : '<span/>';
                var filedownload = $('<td/>').append(dlLink);
                var $row = $('<tr/>').append(filename).append(filesize).append(fileview).append(filedownload);
                $row.attr('dblclick', "getDrilldownFile('" + file.mimeType + "','" + file.id + "')");
                $('.file-list tbody').append($row);
            }
        }

        // フォルダのドリルダウン
        function getDrilldownFile(mime, id) {
            if (mime === 'application/vnd.google-apps.folder') {
                clearList();
                parentId = id;
                getFileList(null, id).then(function (objFileList) {
                    viewFileList(objFileList);
                });
            }
        }

        function clearList() {
            $('.file-list tbody *').remove();
        }

        // 追加取得
        function nextPage() {
            getFileList(nextPageToken, parentId).then(function (objFileList) {
                viewFileList(objFileList);
            });;
        }
    </script>
</head>

<body>
    <table class="table table-striped file-list">
        <thead>
            <th>ファイル名</th>
            <th>サイズ</th>
            <th>表示</th>
            <th>ダウンロード</th>
        </thead>
        <tbody>
        </tbody>
    </table>
    <button type="button" onclick="nextPage();" class="next-page btn btn-primary btn-lg btn-block">次</button>
</body>

</html>
```

# 解説

## フォルダとファイルの一覧の取得

objParamではファイル一覧を取得する際の各種パラメータをオブジェクトで指定しています。
指定できるプロパティの一覧は[こちら](https://developers.google.com/drive/v3/reference/files/list)になります。
fieldsは戻り値で含めてほしい項目として指定できます。
```nexPageToken```はpageSizeで指定した数以上にファイルまたはフォルダがあった際に、次ページの一覧を取得する際のトークンになります。
```files(id, name, kind...)```は戻り値のfilesプロパティの配下の項目（ファイルのメタ情報の項目）を指定できます。
指定できるファイルのメタ情報は[こちら](https://developers.google.com/drive/v3/reference/files)を参照してください。

```js
// リクエストパラメータ
var objParam = {
    pageSize: 10,
    orderBy: 'folder,modifiedTime',
    q: 'trashed=false',
    fields: 'files(id, name, kind, size, mimeType, lastModifyingUser, modifiedTime, iconLink, owners, folderColorRgb, shared, webViewLink, webContentLink), nextPageToken'
};

// リクエストオブジェクトの生成
var objReq = googleDriveClient.drive.files.list(objParam);
objReq.execute(function (resp) {
    resolve(resp);
});
```

### マイフォルダ配下のファイルの一覧の取得

~~**Google Driveのマイフォルダ配下のファイルおよびフォルダ一覧を取得する方法がわかりませんでしたが、もしご存じの方がいればご教示頂けると助かりますm(__)m**~~

qプロパティに```'"root" in parents'```でマイフォルダ配下のファイルとフォルダを取得できます。

@howdy39さんご教授ありがとうございました！

### ファイル取得時の絞り込み

qプロパティにクエリを追加することで取得条件を追加できます。
クエリで追加可能なパラメータは[こちら](https://developers.google.com/drive/v3/web/search-parameters)になります。

```js
q: 'trashed=false'
```

## フォルダ配下のファイル一覧の取得

ファイル取得する時のクエリに「フォルダID in parents」を追加で指定することで、
特定のフォルダ配下のファイル一覧を取得することができます。


```js
if (strParentId) {
  objParam.q += ' and ' + '"' + strParentId + '" in parents';
}
```

## 次ページのファイル取得

ファイル一覧の取得で得られた```pageToken```をリクエストパラメータに追加することで次ページのファイル一覧が追加取得されます。

```js
if (strPageToken) {
  objParam.pageToken = strPageToken;
}
```

## ファイルのプレビュー

レスポンスで得られたファイル、フォルダのメタ情報のwebViewLink（v2はalternateLink）項目にアクセスするといつものGoogle driveのプレビューが表示されます

## ファイルのダウンロード

レスポンスで得られたメタ情報のwebContentLink項目にアクセスするとファイルのダウンロードが開始されます。

## リビジョン別のファイルの取得

Google Driveの版管理で保存されているファイルを取得することができます。
上記のサンプルコードにはありませんが、revisionsメソッドを利用した簡単なサンプルコード（V2版）です。
V3のリファレンスは[こちら](https://developers.google.com/drive/v3/reference/revisions/get)
V2のリファレンスは[こちら](https://developers.google.com/drive/v2/reference/revisions/get)

リクエストパラメータにfieldsプロパティを追加することで、上記同様に取得するメタ情報の項目を指定することができます。
V3のレスポンス値は[こちら](https://developers.google.com/drive/v3/reference/revisions#resource)になります。
リファレンスにもありますようにV3ではファイル取得用のURIがメタ情報で取得することができないので、~~ファイルそのものを取得したい場合はV2を利用してください。（V3でのリビジョン別のファイル取得の方法がお分かりの場合は教えて頂ける幸いです）~~
ファイルURIで取得したい場合は、V2を利用してください。V3でファイルの取得は下記の「API V3でのリビジョン別のファイルダウンロードの方法」をご参照ください。

V2ではfieldsに「downloadUrl」を含めることでファイルのダウンロードリンクを取得することができます。

```js
// API V2

var objParam = {
  fileId: 'ファイルID',
  revisionId: 'リビジョンID',
  fields: 'id, mimeType, fileSize, downloadUrl'
}

googleDriveClient.drive.revisions.get(objParam).then(function(objRevision) {
  // 指定したファイルの特定のリビジョンのメタ情報
  console.log(objRevision);
});
```

### API V3でのリビジョン別のファイルダウンロードの方法
リクエストパラメータにaltプロパティを追加することでファイルの実体を取得できます

```js
var objParam = {
  fileId: 'ファイルID',
  revisionId: 'リビジョンID',
  alt: 'media' // このパラメータを付与することでレスポンスがメタ情報ではなく、ファイルそのものが返される
}

var mimeType = 'image/jpeg';  // ファイルのmime typeに合わせて変更してください
var fileName = 'myfile';

googleDriveClient.drive.revisions.get(objParam).then(function(objRevisionFile) {
  var strBase64 = window.btoa(objRevisionFile.body);  // バイナリデータをbase64にデコード
  var dataUrl = 'data:' + mimeType +  ';base64,' + strBase64;
  var link = document.createElement('a');
  link.href = dataUrl ;
  link.download = 'strFileName';
  link.click();
  (window.URL || window.webkitURL).revokeObjectURL(dataUrl );
});
```

@howdy39さんありがとうございました！


# リポジトリ

https://github.com/comefigo/get-google-drive-files-sample