今回のアップデート(2016/05/08 の定期メンテナンスにおけるkintone API、User API更新情報)で登場したkintone.proxy.upload()ですが、ドキュメントを見てもなかなかリクエスト方法・使い方がよくわかりませんでした。ファイルアップロードと聞くと色々夢が広がりますが、結構クセがあるようで、今回色々調べ、試してみたこと、そして分かったことを全て書き出したいと思います。短編版にとても入りきれなかったので、こちらに切り出したのですが、何となく結果だけ知りたい方は短編版を御覧ください。

アプローチ方法

kintone.proxy.upload()のリクエストの仕方、使い方を見出すにあたって、大きく2つの流れを考えました。

(1)APIとなれば基本的にcURLコマンドでコール出来ますので、kintone.proxy.upload()に対応するcURLコマンドを見つけようと思います。
※以前cybozu.com developer networkのTipsとして「kintoneマッシュアップのための豆知識(curlコマンドとkintone.proxy()の対応)」という記事でkintone.proxy()とcURLコマンドの対応関係を明らかにしましたが、これと同じアプローチです。

(2)また、cURLコマンドやkintone.proxy.upload()でコールしたリクエスト内容をRequestBinに食わせることで、特にkintone.proxy.upload()からのリクエストをプロキシがどのようなリクエストに置き換えて送信しているのかをウォッチします。そうすることで、kintone.proxy.upload()でアップロードできるAPIの形式を確認すると共に、kintone.proxy.upload()からどのようにリクエストすれば外部サービスに渡せるのかを紐けるだろうという意図です。

調べる

まず、(1)のアプローチに基いて、ファイルアップロードAPIを備えたサービスでcURLコマンドのリクエスト例があるサービスを探すことから始めてみました。探し始めて5分、探し当てたのが「transfer.sh」というファイル共有サービスでした。10GBまでのファイルを14日間URLで共有できるというものです。kintoneに添付したファイルでkintoneから外のコミュニケーションスペースに共有したいといった時に便利そうなサービスです。ここで、サンプルに載っていたコマンドが、こんな感じです。

$ curl --upload-file ./logo.jpg https://transfer.sh/logo.jpg

認証もなく、シンプルなリクエストです。cURLコマンドでファイルアップロードとなると、Content-Typeが「application/x-www-form-urlencoded」に対応する「-d」や「multipart/form-data」に対応する「-F」はよく見かけますが、「–upload-file」は初めてです。しかし、kintone.proxy.upload()もRAWデータのアップロードとありますし、シンプルです。ひとまず、これをkintone.proxy.upload()で置き換えるべく書いてみました。※アプリは短編版に記載されているものを利用しています。

  // kintoneの添付ファイルをBlobで取得する
  function getBlob(fileKey, fileName, callback) {
    var apiurl = '/k/v1/file.json?fileKey=' + fileKey;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', apiurl, true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); //これが無いとIE,FFがNG
    xhr.responseType = "blob";
    var blob = xhr.responseType;

    xhr.onload = function() {
      var blob = xhr.response;
      callback(blob);
    };
    xhr.send();
  }

  // transfer.shにファイルをアップロードする
  function uploadToService(fileName, blob) {
    var url = 'https://transfer.sh/' + encodeURIComponent(fileName);
    return kintone.proxy.upload(
      url,
      'POST', {}, {
        'format': 'RAW',
        'value': blob
      }
    );
  }

  // コンソールで実行
  new kintone.Promise(function(resolve, reject) {
    getBlob(fileKey, fileName, function(blob) { // 添付ファイルの取得
      resolve(blob);
    });
  }).then(function(blob) {
    return uploadToService(fileName, blob); // transfer.sh へのアップロード
  }).then(function(resp) {
    var url = resp[0];
    console.log(url);
  })

これは通りませんでした。そこで、・・・

$ curl --upload-file ./logo.jpg https://transfer.sh/logo.jpg

のコマンドで、リクエスト先をRequestBinに変えて、–upload-fileオプションにおけるリクエスト内容を確認します。

$ curl --upload-file ./logo.jpg http://requestb.in/10zrdud1 # リクエスト
ok # レスポンス

スクリーンショット_2016-05-09_1_51_34

なるほど、–upload-fileのメゾッドはPUTが標準のようです。ということで、PUTに変更して再度トライします。

  // kintoneの添付ファイルをBlobで取得する
  function getBlob(fileKey, fileName, callback) {
    var apiurl = '/k/v1/file.json?fileKey=' + fileKey;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', apiurl, true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); //これが無いとIE,FFがNG
    xhr.responseType = "blob";
    var blob = xhr.responseType;

    xhr.onload = function() {
      var blob = xhr.response;
      callback(blob);
    };
    xhr.send();
  }

  // transfer.shにファイルをアップロードする
  function uploadToService(fileName, blob) {
    var url = 'https://transfer.sh/' + encodeURIComponent(fileName);
    return kintone.proxy.upload(
      url,
      'POST', {}, {
        'format': 'RAW',
        'value': blob
      }
    );
  }

  // コンソールで実行
  new kintone.Promise(function(resolve, reject) {
    getBlob(fileKey, fileName, function(blob) { // 添付ファイルの取得
      resolve(blob);
    });
  }).then(function(blob) {
    return uploadToService(fileName, blob); // transfer.sh へのアップロード
  }).then(function(resp) {
    var url = resp[0];
    console.log(url);
  })

今度は通りました!ここまでで分かったのは、cURLコマンドの–upload-fileオプションはkintone.proxy.upload()ではPUTのファイルアップロードのリクエストと等価ということになります。

ここで、(2)のアプローチとして、リクエストが成功したkintone.proxy.upload()のパターンのリクエスト先をRequestBinに変えてkintone.proxy.upload()、つまりプロキシから成功させることが出来るリクエスト形式を確認しておきます。
スクリーンショット_2016-05-09_2_03_45

なるほど、ボディの形式はドキュメントにあるように

{
  "format": "RAW",
  "value": Blob型(File型を含む)データ
}

と、本当にRAWなデータを受け付けるようです。

考察

長々と書きましたが、まとめると、
・「curl –upload-file」とkintone.proxy.upload()のPUTメソッドが対応している
  ※「curl -F」、「curl -d」との対応は現状見出されていない
・以下の様なRAWデータ形式のファイルアップロード仕様のAPIを有するサービスで利用できる(ヘッダやクエリで認証情報をのせるのにも対応できそう)

実は、やりたいのは、kintoneのファイルアップロードやSendGridの添付ファイル付きメール送信に対応している「multipart/form-data」形式(「curl -F」に対応)のアップロードだったのですが、どうも思ったようにはいきませんでした。

ちょっと難解なので、わかり易い利用用途が出てくることを期待しています。

 


株式会社ジョイゾー