LoginSignup
41
42

More than 3 years have passed since last update.

クラウドストレージ「Box」にAPIを使ってファイルをアップロードする

Last updated at Posted at 2020-01-13

概要

クラウドストレージのBoxにAPI経由でファイルのアップロードを行う必要があったのですが、
調べてもあまり情報がなかったので記載しておきます。

環境

開発環境はMacでNodebrewを使っています。

$ nodebrew 
nodebrew 1.0.1
$ node -v
v12.14.1

カスタムアプリの作成と承認

カスタムアプリの作成

BoxAPIを使うためにまずカスタムアプリを作成します。

デベロッパーコンソールにアクセスしてBoxアカウントにログインします。
https://app.box.com/developers/console

アプリの新規作成を押下します。

アプリの種類でカスタムアプリを選択します。

スクリーンショット 2020-01-13 1.13.16.png

認証方法でJWTを使用したOAuth 2.0 (サーバー認証)を選択します。

スクリーンショット 2020-01-13 1.13.30.png

アプリの名前を入力してアプリの作成を押下します。

スクリーンショット 2020-01-13 1.13.55.png

アプリを作成するとデベロッパーコンソールのマイアプリに追加されるので、
作成したアプリを選択して左のメニューから構成画面を表示します。

スクリーンショット 2020-01-13 1.15.31.png

ここに表示されているDeveloperトークンを使ってAPIを実行することもできますが、
今回は認証キーを使用します。

構成画面内に公開キーの追加と管理という項目があるので、そちらから公開/秘密キーペアを生成します。
※アカウントに二段階認証が設定されている必要があります。

スクリーンショット 2020-01-13 1.16.50.png

キーペアを生成すると認証情報が記載されたJSONファイルが保存されるので、こちらを使って認証を行います。

カスタムアプリの承認

次にBoxアカウントにカスタムアプリの承認を行います。

Boxアカウントの管理コンソールからEnterprise設定を開いて
アプリ→カスタムアプリケーション→新しいアプリケーションを承認を押下します。

スクリーンショット 2020-01-13 1.19.50.png

APIキーの入力画面が表示されるので、
先ほど保存したJSONファイルの中のclientIDを入力して承認します。

スクリーンショット 2020-01-13 1.22.28.png

これでカスタムアプリからAPIを実行する準備ができました。

BoxSDKからAPIの実行

フォルダ内の項目一覧の取得

BoxAPIにはPythonやJAVAのSDKも用意されていますが、今回はbox-node-sdkを使って実行してみます。
https://github.com/box/box-node-sdk

APIリファレンス
https://developer.box.com/jp/reference/

まず適当なフォルダを作成してbox-node-sdkをインストールします。

$ mkdir box-app
$ cd box-app/
$ npm init -y
$ npm install box-node-sdk

作成したフォルダ内に認証情報のJSONファイルを保存しておき、
以下のようなスクリプトを作成します。

こちらの処理では指定したフォルダID内の項目の一覧を取得するAPIを実行しています。
フォルダID'0'はルートディレクトリのIDです。
https://developer.box.com/jp/reference/get-folders-id-items/

script.js
const BoxSDK = require('box-node-sdk');

// 認証キーの読み込み
const sdkConfig = require('./config.json');
const sdk = BoxSDK.getPreconfiguredInstance(sdkConfig);

const client = sdk.getAppAuthClient('enterprise');

// フォルダ内の項目の取得
client.folders.getItems('0')
    .then(folder => {
        console.log(folder);
    })
    .catch(err => {
        console.log(err);
    })

APIを実行してみます。

$ node script.js 
{
  total_count: 0,
  entries: [],
  offset: 0,
  limit: 100,
  order: [
    { by: 'type', direction: 'ASC' },
    { by: 'name', direction: 'ASC' }
  ]

実行するとAPIで取得した項目一覧が出力されますが、
もし自分のBoxアカウントのルートディレクトリにファイルやフォルダを保存していたとしても
ここではなにも表示されないと思います。

ここで取得しているルートディレクトリというのはカスタムアプリ(というアカウント)のルートディレクトリとなるため、
自分のBoxアカウントのルートディレクトリとは別の場所になります。

これだとBoxSDKを使っても結果がわかりづらいのでBoxアカウントとの共有フォルダを作成します。

共有フォルダの作成

まずブラウザで自分のBoxアカウントにアクセスして適当なフォルダを作成します。

管理コンソールからユーザーとグループを開いて
グループ→作成を押下します。

スクリーンショット 2020-01-13 1.06.02.png

グループ名を入力して権限設定でグループメンバーを選択します。

スクリーンショット 2020-01-13 1.28.00.png

メンバーを追加を押下してユーザーの入力欄にカスタムアプリ名を入力すると
サジェストが表示されるのでそちらを選択して追加します。

スクリーンショット 2020-01-13 1.28.52.png

最後にフォルダを共有を押下して先ほど作成したフォルダを選択して完了します。

スクリーンショット 2020-01-13 1.30.07.png

これでカスタムアプリとフォルダの共有を行なっているグループが作成されました。

スクリーンショット 2020-01-13 1.31.23.png

もう一度APIを実行してみると今度は共有フォルダが取得されていることが確認できます。

$ node script.js 
{
  total_count: 1,
  entries: [
    {
      type: 'folder',
      id: '99896711320',
      sequence_id: '0',
      etag: '0',
      name: 'shared'
    }
  ],
  offset: 0,
  limit: 100,
  order: [
    { by: 'type', direction: 'ASC' },
    { by: 'name', direction: 'ASC' }
  ]
}

ファイルアップロード

共有フォルダが作成できたのでファイルアップロードAPIを実行します。
https://developer.box.com/jp/reference/post-files-content/

ソースを以下のように修正します。

script.js
const BoxSDK = require('box-node-sdk');
// 追加
const fs = require('fs');

// 認証キーの読み込み
const sdkConfig = require('./config.json');
const sdk = BoxSDK.getPreconfiguredInstance(sdkConfig);

const client = sdk.getAppAuthClient('enterprise');

// フォルダ内の項目の取得
client.folders.getItems('0')
    .then(folder => {
        // 追加
        fs.readFile('./upload_file.txt', (err, data) => {
            if (err) {
                console.log(err);
                return;
            }
            // ファイルアップロード
            client.files.uploadFile(folder.entries[0].id, 'upload_file.txt', data)
                .then(file => {
                    console.log(file);
                })
                .catch(err => {
                    console.log(err);
                })
        })
    })
    .catch(err => {
        console.log(err);
    })

スクリプトを実行するとアップロードしたファイルの情報が出力されます。

$ node script.js 
{
  total_count: 1,
  entries: [
    {
      type: 'file',
      id: '595943878038',
      file_version: [Object],
      sequence_id: '0',
      etag: '0',
      sha1: '',
      name: 'upload_file.txt',
      description: '',
      size: 247379,
      path_collection: [Object],
      created_at: '2020-01-12T08:54:09-08:00',
      modified_at: '2020-01-12T08:54:09-08:00',
      trashed_at: null,
      purged_at: null,
      content_created_at: '2020-01-12T08:54:09-08:00',
      content_modified_at: '2020-01-12T08:54:09-08:00',
      created_by: [Object],
      modified_by: [Object],
      owned_by: [Object],
      shared_link: null,
      parent: [Object],
      item_status: 'active'
    }
  ]
}

Boxアカウントでフォルダを確認するとファイルが保存されています。

スクリーンショット 2020-01-13 1.56.28.png

※フォルダ内に同名ファイルがある状態でアップロードを行うと409エラーが返ってくるので
その場合はファイル名を変更するかファイルのバージョンアップAPIを実行してください。
https://developer.box.com/jp/reference/post-files-id-content/

大容量ファイルのアップロード

サイズの小さいファイルは上の方法でアップロードを行えば良いのですが、
50MBを超えるファイルは分割アップロードを使用することが推奨されているとリファレンスに記載があります。

分割アップロードAPI
https://developer.box.com/jp/reference/get-files-upload-sessions-id/

ただ、APIリファレンスのやり方だと分割アップロードのセッションの作成、
パーツごとに分割アップロード、アップロードセッションのコミットなど複数のAPIを実行する必要があり少し面倒なのですが、
box-node-sdkのドキュメントを見てみるとこれらをまとめて行なってくれる分割アップロード用のAPIが用意されているようです。
https://github.com/box/box-node-sdk/blob/master/docs/files.md#chunked-upload

こちらを使って分割アップロードを試してみます。

サイズが大きいファイルを用意してソースを修正します。
※20MB以下のファイルを分割アップロードするとエラーになります。

script.js
const BoxSDK = require('box-node-sdk');
const fs = require('fs');

// 認証キーの読み込み
const sdkConfig = require('./config.json');
const sdk = BoxSDK.getPreconfiguredInstance(sdkConfig);

const client = sdk.getAppAuthClient('enterprise');

// フォルダ内の項目の取得
client.folders.getItems('0')
    .then(folder => {
        // 修正
        fs.readFile('./large_file.csv', (err, data) => {
            if (err) {
                console.log(err);
                return;
            }
            // 分割ファイルアップロード
            client.files.getChunkedUploader(folder.entries[0].id, data.length, 'large_file.csv', data)
                .then(uploader => uploader.start())
                .then(file => {
                    console.log(file);
                })
                .catch(err => {
                    console.log(err);
                })
        })
    })
    .catch(err => {
        console.log(err);
    })

スクリプトを実行するとアップロードしたファイルの情報が出力されます。

$ node script.js 
{
  total_count: 1,
  entries: [
    {
      type: 'file',
      id: '595967596582',
      file_version: [Object],
      sequence_id: '0',
      etag: '0',
      sha1: '',
      name: 'large_file.csv',
      description: '',
      size: 20243278,
      path_collection: [Object],
      created_at: '2020-01-12T09:31:27-08:00',
      modified_at: '2020-01-12T09:31:27-08:00',
      trashed_at: null,
      purged_at: null,
      content_created_at: '2020-01-12T09:31:27-08:00',
      content_modified_at: '2020-01-12T09:31:27-08:00',
      created_by: [Object],
      modified_by: [Object],
      owned_by: [Object],
      shared_link: null,
      parent: [Object],
      item_status: 'active'
    }
  ]
}

Boxアカウントで確認すると大容量ファイルも保存されていることが確認できます。

おわりに

今回BoxAPIをいくつか試していたのですが、検索APIでファイルやフォルダの検索を行うと
作成してから少し時間が経ったものでないと検索に引っかかりませんでした。

もし原因を知っている方がいれば教えていただけると助かります。

→インデックスの作成に時間がかかるためでした。
https://community.box.com/t5/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%A8%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AE%E7%AE%A1%E7%90%86/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB-%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%81%AE%E6%A4%9C%E7%B4%A2/ta-p/36911#search_hdsiw

41
42
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
42