ReactプロジェクトでBox TS SDKを使用する

Yuko Taniguchi
Box Developer Japan Blog
15 min readJan 16, 2024

Box TS SDKは、多くの新規ユーザーを獲得して勢いを増しています。前回の記事では、静的なHTMLページでSDKの使用を開始する簡単な例を紹介しました。今回は、それを次のレベルに進めて、このSDKをReactベースのアプリに組み込みます。

Boxアプリケーションの設定については、前回の記事を確認してください。ここではコーディングを開始しましょう。

⚠️ 重要: 開発者コンソールの [構成] タブの [CORSドメイン] の設定に、ローカルのホストアドレスが含まれ、末尾にスラッシュがないことを確認してください。

シンプルなReactアプリには、あるユーザーのBoxアカウントのファイルとフォルダが表示されます。また、ファイルのダウンロードも可能にする予定です。

開発者トークンが入力され、ルートにあるBoxフォルダが表示されているアプリ画面

CLIコマンドを使用して、Reactアプリを一から作成します。

npx create-react-app NAME_OF_YOUR_APP

SDKを使用するためにプロジェクトをTSベースにする必要はないことにご注意ください。ディレクトリを新しく作成したプロジェクトに変更します。

cd NAME_OF_YOUR_APP

Box TS SDKをインストールします。これは自動生成されたSDKのベータ版であり、頻繁に改善されていることを考慮してください。このブログ記事では、v0.1.8がベースとなっています。

npm install box-typescript-sdk-gen

プロジェクトを実行します。

npm start

このアプリは、ユーザーがBoxの開発者トークンを入力できる入力フィールドと、ルートフォルダのコンテンツが表示されるシンプルな表で構成されます。さらに、ユーザーは、選択したフォルダを開いたり、ファイルをダウンロードしたりできるようになります。

注: このチュートリアルでは、コードがApp.jsファイルに含まれています。より大規模なプロジェクトでは、専用のスマートコンポーネントを自由に記述してください。

まず、ReactのMUIコンポーネントライブラリを依存関係として追加して、スタイルの指定を省略します。ターミナルで次のように入力します。

npm i @mui/material

App.jsで、MUIから以下のコンポーネントをインポートします。

import "./App.css";
import React from "react";
import {
Button,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TextField,
} from "@mui/material";

BoxClientBoxDeveloperTokenAuthをインポートします。

import { BoxClient, BoxDeveloperTokenAuth } from "box-typescript-sdk-gen";

これですべての設定が完了したので、アプリのコンポーネントロジックに取りかかりましょう。

  • Boxから取り込んだデータを格納するためのitemsの初期状態
  • clientの初期状態
  • ユーザー認証用のupdateTokenメソッド
  • Boxからデータを取り込むためのgetFilesメソッド
function App() {
const [items, setItems] = React.useState([]);
const [client, setClient] = React.useState(null);

let updateToken = (value) => {
let auth = new BoxDeveloperTokenAuth({
token: value.target.value,
});
let boxClient = new BoxClient({ auth });
setClient(boxClient);
};
let getFiles = async (folderId) => {
if (client === null) {
alert("Please enter a developer token");
return;
}
let entries = (await client.folders.getFolderItems(folderId)).entries;
setItems(entries);
};
// Additional code follows here
...
}
export default App;

マークアップに取りかかりましょう。MUIのコンポーネントを使用して、以下を追加します。

  • ユーザーが開発者トークンを入力するためのTextField。変更時に、トークン変数を更新します。
  • ルートフォルダからデータを取り込むためのButton
  • TableHead、TableRow、TableCell、TableBodyを含むTableContainerを使用した、表のマークアップ

TableBodyでは、項目を反復処理し、ファイルとフォルダのid、name、typeを表示します。

// Continue in App component

return (
<div className="App">
<header className="App-header">
<TextField
label="Developer Token"
variant="outlined"
onChange={updateToken}
></TextField>
<br />
<Button variant="contained" onClick={() => getFiles("0")}>
Get Root Folder
</Button>
</header>
<Paper>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>ID</TableCell>
<TableCell>Name</TableCell>
<TableCell>Type</TableCell>
<TableCell>Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map((item) => (
<TableRow key={`${item.type}-${item.id}`}>
<TableCell>{item.id}</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell>{item.type}</TableCell>
<TableCell>TODO</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
</div>
);

すばらしいです。開発者トークンを送信した後、Boxアカウントのデータがアプリに表示されるかどうかを確認してください。

開発者トークンは、Box開発者コンソールで生成できます。

⚠️ 重要: 開発者トークンの有効期間は1時間のため、無効になったら更新してください。

次に、ダウンロード操作を処理するための新しいメソッドを追加します。この処理では、一時的なアンカー要素を作成し、ローカルのダウンロードをトリガーして、そのアンカーを削除します。

...

function App() {

...

let downloadFile = async (fileId) => {
const fileInfo = await client.files.getFileById(fileId);
const byteStream = await client.downloads.downloadFile(fileId);
const destHandler = await window
.showSaveFilePicker({
suggestedName: fileInfo.name,
})
.catch((err) => {
// The user cancelled the save prompt
console.log(err);
});
if (destHandler === undefined) {
return;
}
const writableStream = await destHandler.createWritable();
byteStream.pipeTo(writableStream);
};

...
}

export default App;

最後に、作業中の表のセルにボタンを追加します。ファイルの種類に応じて異なるボタンを表示して、適切な操作を実行できるようにしましょう。このボタンは、フォルダの場合はgetFiles関数をトリガーし、ファイルの場合はダウンロード操作をトリガーします。また、リンクの場合は新しいタブを開きます。

{/* Adjust the markap with additional TableCell */}

<TableBody>
{items.map((item) => (
<TableRow key={`${item.type}-${item.id}`}>
<TableCell>{item.id}</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell>{item.type}</TableCell>

{/* Display adequate UI element depending on item type */}
<TableCell>
{item.type === "file" ? (
<button onClick={() => downloadFile(item.id)}>
Download
</button>
) : item.type === "folder" ? (
<button onClick={() => getFiles(item.id)}>Open</button>
) : item.type === "web_link" ? (
<a href={item.url} target="_blank" rel="noreferrer">
<button>Open</button>
</a>
) : null}
</TableCell>

</TableRow>
))}
</TableBody>

{/* Display Box data in table */}

以上です。[Download (ダウンロード)] ボタンをクリックすると、ファイルをローカルマシンにダウンロードできるようになります。前述のとおり、この操作を許可するには、開発者コンソールで [Boxに格納されているすべてのファイルとフォルダへの書き込み] チェックボックスをオンにしてください。エラー処理については、まず、[構成] タブでBoxアプリの設定を確認します。

おすすめのアプリは非常に簡単な例です。本番環境に対応したプロジェクトの場合は、発生する可能性のあるエラーを必ず処理するようにしてください。

必要なコードをすべて追加した後のApp.js全体を以下に示します。

import "./App.css";
import React from "react";
import {
Button,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TextField,
} from "@mui/material";

import { BoxClient, BoxDeveloperTokenAuth } from "box-typescript-sdk-gen";

function App() {
const [items, setItems] = React.useState([]);
const [client, setClient] = React.useState(null);
let updateToken = (value) => {
let auth = new BoxDeveloperTokenAuth({
token: value.target.value,
});
let boxClient = new BoxClient({ auth });
setClient(boxClient);
};

let getFiles = async (folderId) => {
if (client === null) {
alert("Please enter a developer token");
return;
}
let entries = (await client.folders.getFolderItems(folderId)).entries;
setItems(entries);
};

let downloadFile = async (fileId) => {
const fileInfo = await client.files.getFileById(fileId);
const byteStream = await client.downloads.downloadFile(fileId);
const destHandler = await window
.showSaveFilePicker({
suggestedName: fileInfo.name,
})
.catch((err) => {
// The user cancelled the save prompt
console.log(err);
});
if (destHandler === undefined) {
return;
}
const writableStream = await destHandler.createWritable();
byteStream.pipeTo(writableStream);
};

return (
<div className="App">
<header className="App-header">
<TextField
label="Developer Token"
variant="outlined"
onChange={updateToken}
></TextField>
<br />
<Button variant="contained" onClick={() => getFiles("0")}>
Get Root Folder
</Button>
</header>
<Paper>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>ID</TableCell>
<TableCell>Name</TableCell>
<TableCell>Type</TableCell>
<TableCell></TableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map((item) => (
<TableRow key={`${item.type}-${item.id}`}>
<TableCell>{item.id}</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell>{item.type}</TableCell>

<TableCell>
{item.type === "file" ? (
<button onClick={() => downloadFile(item.id)}>
Download
</button>
) : item.type === "folder" ? (
<button onClick={() => getFiles(item.id)}>Open</button>
) : item.type === "web_link" ? (
<a href={item.url} target="_blank" rel="noreferrer">
<button>Open</button>
</a>
) : null}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
</div>
);
}

export default App;

コード全体は、こちらのリポジトリでご確認ください。

⚠️ Box Node.js SDKを使用している場合は、移行ガイドをご確認のうえ、Box TS SDKの使用を開始してください。

🦄 Box Platformの上級者から学びたい場合は、サポートや知識共有のためのBox Developer Community (英語のみ) にご参加ください。

--

--