Google API 第32回

投稿者: | 2016年6月16日

前回に引き続き、Google Drive APIについてです。
今回はChangesを用いたリクエストとファイルのアップロードについて紹介します。

■Changes
Changesを用いたリクエストでは、ファイルの変更内容を取得することができます。

○リクエストと結果
Changesを用いてリクエストをするには下記のメソッドを使用します。
gapi.client.drive.changes.getStartPageToken()
・・・変更内容を取得するためのページトークンを取得
gapi.client.drive.changes.list()・・・変更内容を取得
gapi.client.drive.changes.watch()・・・購読の変更を取得

・getStartPageTokenの場合
gapi.client.drive.changes.getStartPageToken({});を実行するだけです。

リクエスト結果は下記の通りです。
kindは常にdrive#startPageTokenという文言です。
startPageTokenは変更内容を一覧取得するためのページトークンです。

{
 "kind": "drive#startPageToken",
 "startPageToken": "15241"
}

・listの場合
ファイルを変更する前に取得したページトークン、リクエスト結果を取得するためのfieids
が必要になります。
gapi.client.drive.changes.list({‘pageToken’: pageToken, ‘fieids’: changes});
fieidsを指定しないリクエストを行うこともできます。
その場合のリクエスト結果はkind、newStartPageToken、changes[].kind、changes[].fileId、
changes[].removed、changes[].timeのみの情報となります。
gapi.client.drive.revisions.list({‘pageToken’: token});

必要であればincludeRemoved、pageSize、restrictToMyDrive、spaces、fields
を指定することもできます。
includeRemovedは削除したファイルを含むかどうかを示します。
falseにすると削除したファイルを含みません。デフォルトはtrueです。
pageSizeはページごとに取得するファイルの数です。
restrictToMyDriveは自分のドライブ内で変更されたファイルのみを取得するどうかです。
trueにすると共有やアプリケージョンで変更されたファイルなどは除外され、
自分のドライブ内で変更されたファイルのみを取得します。
spaceには「drive」「appDataFolder」「photos」の文字列で指定できます。
指定するとそれぞれの文字列に応じてファイルが絞り込まれます。
「drive」はGoogleドライブ内、「appDataFolder」はアプリのデータフォルダ、
「photos」はGoogleフォト内です。

リクエストの結果は下記の通りです。
kindは常にdrive#changeListという文言です。
nextPageTokenは次のページのファイルを取得するためのトークンです。
changes[].kindは常にdrive#changeという文言です。
changes[].fileIdはファイルのIDです。
changes[].removedは削除されているかどうかを示します。
trueになっている場合、ファイルは削除されています。
changes[].timeは変更された日時です。

{
 "kind": "drive#changeList",
 "nextPageToken": "8290",
 "changes": [
  {
   "kind": "drive#change",
   "fileId": "0B3gdltLSXnCsTzdnMDV4VXXXXX",
   "removed": true,
   "time": "2015-09-16T09:37:21.436Z"
  },
  {
   "kind": "drive#change",
   "fileId": "0B3gdltLSXnCsM01QRVNaLVXXXXX",
   "removed": true,
   "time": "2015-09-16T09:37:24.469Z"
  },
  {
   "kind": "drive#change",
   "fileId": "0B3gdltLSXnCsRXNLVkYwNDXXXXX",
   "removed": true,
   "time": "2015-09-16T09:37:27.483Z"
  },
  {
   "kind": "drive#change",
   "fileId": "0B3gdltLSXnCscTNrWDRwWEXXXXX",
   "removed": true,
   "time": "2015-09-16T09:37:30.046Z"
  },
  {
   "kind": "drive#change",
   "fileId": "0B3gdltLSXnCsN1RfRXFqQ1XXXXX",
   "removed": true,
   "time": "2015-10-11T18:45:17.555Z"
  },
...
 ]
}

・watchの場合
用途が特殊なので省略します。

■ファイルのアップロード
Google Driveでのアップロード方法は、
Simple upload、Multipart upload、Resumable uploadがあります。
Simple uploadは5MB以下の小さなファイルをアップロードするための方法です。
Multipart uploadは小さなファイルとメタデータをアップロードするための方法です。
Resumable uploadは大きなファイルをアップロードするための方法です。

今回は一般的なアップロード方法であるMultipart uploadについて紹介します。

○Multipart upload
下記のソースは公式に載っている画像のアップロード方法です。

POST /upload/drive/v3/files?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: number_of_bytes_in_entire_request_body

--foo_bar_baz
Content-Type: application/json; charset=UTF-8

{
  "name": "My File"
}

--foo_bar_baz
Content-Type: image/jpeg

JPEGデータ 
--foo_bar_baz--

上記のソースをJavaScriptのソースに直します。
※Host:~はリクエスト時に解決されます。
※Authorization:~はリクエスト時に自動で送信されます。
※Content-Length:~は今回のリクエストでは使用しないので省略します。

// リクエストするURL
var path = '/upload/drive/v3/files';
var method = 'POST';
var params = {'uploadType': 'multipart'};

// リクエスト部分を識別するための適当な文字列
var boundary = '314159265358979323846';
var headers = {'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'};

// 画像名
var imgame = 'My File';
var metadata = {
                'name': imgame
               };
// 画像のMIMEタイプ
var contentType = 'image/jpeg';

// 画像をbase64データに変換
var base64Data = btoa(file);

// 画像のエンコード方式
var encoding = 'Content-Transfer-Encoding: base64';

var CRLF = '\r\n';

// リクエストボディ作成
var body
    = '--' + boundary                                 + CRLF
    + 'Content-Type: application/json; charset=UTF-8' + CRLF
    + CRLF
    + JSON.stringify(metadata)                        + CRLF
    + '--' + boundary                                 + CRLF
    + 'Content-Type: ' + contentType                  + CRLF
    + encording                                       + CRLF
    + CRLF
    + base64Data                                      + CRLF
    + '--' + boundary + '--';

// リクエスト作成
var request = gapi.client.request({
    'path'   : path,
    'method' : method,
    'params' : params,
    'headers': headers,
    'body'   : body
});

// リクエスト送信・結果
request.execute(function(res){
    alert(res.result.name + "のアップロードが完了しました。");
}

アップロードが完了するとGoogleドライブに保存されます。
google_api32-1

5MB程度のファイルだと20秒程でアップロードが終わりました。

以上がChangesを用いたリクエストとファイルのアップロードの仕方です。

Changesを用いたリクエストを活用すると共有しているファイルがあった場合に
ファイルの変更をメールなどで通知したり、ファイルの変更履歴を作成したりすることができます。

ファイルのアップロードに関してはMultipart uploadさえ抑えておけば、
ほとんどのファイルをアップロードすることができます。
付録にソースがありますので、まずは試してみてください。

■Google Drive APIのリクエストについてのまとめ
Google Drive APIのリクエストについて3回に渡り紹介してきました。

Google Drive APIではリクエストを用いると簡単にファイル操作などができると
わかってもらえたと思います。
今回はJavaScriptでのリクエスト方法を紹介しましたが、
他の言語でもJavaScriptと同じようなライブラリが用意されており、
簡単にファイル操作などが行えます。

またGoogle Drive APIを用いると様々な用途のアプリを作成することができます。
例えば、写真アプリと連携させて撮影した画像を自動でGoogleドライブにアップロードするようなアプリを作成したり、特定のフォルダからファイルを定期的にアップロードするようなアプリを作成したりできます。

Google Drive APIを用いたアプリ作成に難しい印象を持たれている方はいると思いますが、
全3回に渡り紹介したリクエストはそれぞれ簡単なものです。
これらの記事をアプリ作成に役立てて頂ければ幸いです。

<参考サイト>
・Google Drive APIのリファレンス

<付録>
・ファイルの変更を取得する簡単なサンプル
※使用する際はCLIENT_IDを自身で作成したクライアントIDに置き換えてください。
またTOKENも置き換えて使用してください。

<html>
  <head>
    <script type="text/javascript">
    var CLIENT_ID = 'CLIENT_ID';

    var SCOPES = ['https://www.googleapis.com/auth/drive'];

    var access_token;

    function checkAuth() {
        gapi.auth.authorize({
            client_id: CLIENT_ID,
            scope: SCOPES,
            immediate: true
        },
        authResult
        );
    }

    function authResult(authResult) {
        var authorizeDiv = document.getElementById('authorize-div');
        if (authResult && !authResult.error) {
            authorizeDiv.style.display = 'none';
            loadAPI();
        }   
        else {
            authorizeDiv.style.display = 'inline';
        }
    }
    function loadAPI() {
        gapi.client.load('drive', 'v3', list);
    }

    function authClick(event) {
        gapi.auth.authorize({
            client_id: CLIENT_ID,
            scope: SCOPES,
            immediate: false
        },
        result
        );
        return false;
    }

    function list() {

        var TOKEN = 'TOKEN';

        gapi.client.drive.revisions.list({'pageToken': TOKEN});
        
        req.execute(function(res) {
            var changes = res.changes;

                document.write(changes[0].fileId + '
'); document.write(changes[0].time + '
'); }); } </script> <script src="https://apis.google.com/js/client.js?onload=checkAuth"> </script> </head> <body> <div id="authorize-div" style="display: none"> <span>Authorize access to Drive API</span> <button id="authorize-button" onclick="authClick(event)"> Authorize </button> </div> </body> </html>

・ファイルをアップロードする簡単なサンプル
※使用する際はCLIENT_IDを自身で作成したクライアントIDに置き換えてください。

<html>
  <head>
    <title>test</title>
  <body>
    <div id="authorize-div" style="display: none">
      <span>Authorize access to Drive API</span>
      <button id="authorize-button" onclick="authClick(event)">
        Authorize
      </button>
    </div>
    <input type="file" id="file">
  </body>    
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script type="text/javascript">
    var CLIENT_ID = 'CLIENT_ID';

    var SCOPES = ['https://www.googleapis.com/auth/drive'];
    
    function checkAuth() {
        gapi.auth.authorize({
            client_id: CLIENT_ID,
            scope: SCOPES,
            immediate: true,
        },
        authResult
        );
    }

    function authResult(authResult) {
        var authorizeDiv = document.getElementById('authorize-div');
        if (authResult && !authResult.error) {
            authorizeDiv.style.display = 'none';
            loadAPI();
        }
        else {
            authorizeDiv.style.display = 'inline';
        }
    }
    function loadAPI() {
        gapi.client.load('drive', 'v3', function(){});
    }

    function authClick(event) {
        gapi.auth.authorize({
            client_id: CLIENT_ID,
            scope: SCOPES,
            immediate: false,
        },
        authResult
        );
        return false;
    }

    inputFile = document.getElementById('file');
    inputFile.addEventListener('change', fileChange, false);
    function fileChange(ev) {

        var target = ev.target;
        var file = target.files[0];
        var filename = file.name
        var contentType = file.type;
        var contentLength = file.size;

        var CRLF = "\r\n"
        var boundary = "314159265358979323846";

        var reader = new FileReader();
        reader.readAsBinaryString(file);
        reader.onload = function (e) {

            var metadata = {
                'name': filename,
                'mimeType': contentType
            };

            var base64Data = btoa(reader.result);

            var multipartRequestBody
                = '--' + boundary                     + CRLF
                + 'Content-Type: application/json'    + CRLF
                + CRLF
                + JSON.stringify(metadata)            + CRLF
                + '--' + boundary                     + CRLF
                + 'Content-Type: ' + contentType      + CRLF
                + 'Content-Transfer-Encoding: base64' + CRLF
                + CRLF
                + base64Data                          + CRLF
                + '--' + boundary + '--';

            var request = gapi.client.request({
                'path': '/upload/drive/v3/files',
                'method': 'POST',
                'params': {'uploadType': 'multipart'},
                'headers': {
                    'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
                },
                'body': multipartRequestBody});
            request.then(function(file){
                alert(file.result.name + "のアップロードが完了しました。");
                inputFile.value = "";
            },function(reason){
                alert(reason)
            });
        }
    }
    </script>
    <script src="https://apis.google.com/js/client.js?onload=checkAuth"></script>
  </head>
</html>