概要
クラウドストレージのBoxにAPI経由でファイルのアップロードを行う必要があったのですが、
調べてもあまり情報がなかったので記載しておきます。
環境
開発環境はMacでNodebrewを使っています。
$ nodebrew
nodebrew 1.0.1
$ node -v
v12.14.1
カスタムアプリの作成と承認
カスタムアプリの作成
BoxAPIを使うためにまずカスタムアプリを作成します。
デベロッパーコンソールにアクセスしてBoxアカウントにログインします。
https://app.box.com/developers/console
アプリの新規作成を押下します。
アプリの種類でカスタムアプリを選択します。
認証方法でJWTを使用したOAuth 2.0 (サーバー認証)を選択します。
アプリの名前を入力してアプリの作成を押下します。
アプリを作成するとデベロッパーコンソールのマイアプリに追加されるので、
作成したアプリを選択して左のメニューから構成画面を表示します。
ここに表示されているDeveloperトークンを使ってAPIを実行することもできますが、
今回は認証キーを使用します。
構成画面内に公開キーの追加と管理という項目があるので、そちらから公開/秘密キーペアを生成します。
※アカウントに二段階認証が設定されている必要があります。
キーペアを生成すると認証情報が記載されたJSONファイルが保存されるので、こちらを使って認証を行います。
カスタムアプリの承認
次にBoxアカウントにカスタムアプリの承認を行います。
Boxアカウントの管理コンソールからEnterprise設定を開いて
アプリ→カスタムアプリケーション→新しいアプリケーションを承認を押下します。
APIキーの入力画面が表示されるので、
先ほど保存したJSONファイルの中のclientIDを入力して承認します。
これでカスタムアプリから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/
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アカウントにアクセスして適当なフォルダを作成します。
管理コンソールからユーザーとグループを開いて
グループ→作成を押下します。
グループ名を入力して権限設定でグループメンバーを選択します。
メンバーを追加を押下してユーザーの入力欄にカスタムアプリ名を入力すると
サジェストが表示されるのでそちらを選択して追加します。
最後にフォルダを共有を押下して先ほど作成したフォルダを選択して完了します。
これでカスタムアプリとフォルダの共有を行なっているグループが作成されました。
もう一度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/
ソースを以下のように修正します。
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アカウントでフォルダを確認するとファイルが保存されています。
※フォルダ内に同名ファイルがある状態でアップロードを行うと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以下のファイルを分割アップロードするとエラーになります。
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でファイルやフォルダの検索を行うと
作成してから少し時間が経ったものでないと検索に引っかかりませんでした。
もし原因を知っている方がいれば教えていただけると助かります。