BOXからファイルをダウンロードする時にSDKを使わないと少し戸惑うのでメモ。
大まかな処理の流れ
利用するAPIの説明はこれです。
https://ja.developer.box.com/reference/get-files-id-content/
このAPIを叩くと、レスポンスが302で帰って来る時は、レスポンスヘッダーでLocation
が戻されます。
このLocation
には、https://dl.boxcloud.com/d/1/b1!V1LhT0hCN....
のようなURLが入ってきます。
このLocation
から実際にファイルをダウンロードします。
レスポンスは2パターンあって、ステータスコードが302
の場合は、ヘッダーにLocation
、202
の場合は、ヘッダーにRetry-After
が戻され、クライアントがファイルをダウンロードできるようになるまでの秒数を示します。
ためしても202
がもどされなかったので、202
が発生して、Retry-After
が戻される時、curlとかaxiosではどういう挙動になるのか不明です。
ここに、curl 7.66.0からRetry-After
に従うようなことがかいてあるけど、どうなんだろう。試してないので動くかわかんないです。
SDKにはこのあたりの処理が間違いなくちゃんと入ってます。
オートメーションとか連携に使うなら、アクセストークンの取り回しなどもあるので、SDKで(特にJWT認証で)使うのがいいでしょうね。
APIをcurlで実行
ダウンロード用URLの取得
まず、Locationをフォローしないかたちで(-L
を付けずに)以下のように実行してみます。
curl -i -X GET "https://api.box.com/2.0/files/690849498295/content" -H "Authorization: Bearer XXXXXXXXXX"
以下のようなレスポンスが帰ってきます。
HTTP/1.1 302 Found
Date: Wed, 16 Dec 2020 02:28:43 GMT
Transfer-Encoding: chunked
Strict-Transport-Security: max-age=31536000
Cache-Control: no-cache, no-store
BOX-REQUEST-ID: 17d4c6d940827c69342f2705eb8df260c
Location: https://dl.boxcloud.com/d/1/b1!V1LhT0hCNCBXXWBMjANGzmCxSWNA0BsyXMMYGOAdG7ZSlBs4FzPrGPjDASb06VFsGc (めちゃくちゃ長いので省略) jLux9WOM./download
Connection: close
ふむふむ、Location
が入ってます。
ダウンロード用URLまで続けて実行
curlでは、-L
を付けて実行すると、上のレスポンスヘッダーのLocationに入ってきたURLに自動的に移動してくれるので、ヘッダーからLocationを取り出すような操作は不要です。
curl -i -X GET "https://api.box.com/2.0/files/690849498295/content" -H "Authorization: Bearer XXXXXXXXXX" -L
以下が帰ってきます。
HTTP/1.1 200 OK
Date: Wed, 16 Dec 2020 06:32:08 GMT
Content-Type: image/png
Content-Length: 86195
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: private
X-Envoy-Upstream-Service-Time: 116
Content-Disposition: attachment;filename="baseball_girl.png";filename*=UTF-8''baseball_girl.png
X-Robots-Tag: noindex, nofollow
Encryption_Policy_Id: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
-L
をつけると、一気にファイルを含んだレスポンスが帰ってきます。
--output
つけてファイルに出力しろって警告してますね。
ファイルに出力するんだったら、-i
で詳細情報だすのは不要です。
ファイルに保存
-i
を外し、-o/--output
で、出力先のファイルを指定すると、ファイルを直接保存可能になります。
APIに対して1発でファイルをダウンロードするコマンドは以下のようになります。
curl -X GET "https://api.box.com/2.0/files/690849498295/content" -H "Authorization: Bearer XXXXXXXXXX" -L -o sample.png
これで一気にファイルがダウンロードできました。
Node.js(Axios)からの実行
Node.jsから実行してみるとこんな感じです。
axiosをつかっていますが、デフォルトで1つめのレスポンスに含まれるLocationをフォローしてくれますね。
ここではresponseType
にstream
を指定して、そのままWriteStreamに書き出してます。
const axios = require("axios");
const fs = require("fs");
const accessToken = "XXXXXXXXXX";
axios
.get("https://api.box.com/2.0/files/690849498295/content", {
headers: { Authorization: `Bearer ${accessToken}` },
responseType: "stream",
})
.then((result) => {
const output = fs.createWriteStream("sample.png");
result.data.pipe(output);
})
.catch((error) => {
console.log(error.message);
});
Box node SDKを使う
ちなみに、Box Node SDKをつかうとこんな感じです。
わざわざアクセストークンを貼るなどせず、JWT認証をつかって認証周りの制御もやってます。
自動化するならBox公式SDKをつかうのが一番らくでしょうね。
const boxSDK = require("box-node-sdk");
const config = require("./config.json");
const fs = require("fs");
const sdk = boxSDK.getPreconfiguredInstance(config);
const client = sdk.getAppAuthClient("enterprise");
client.files.getReadStream("690849498295", null, function (error, stream) {
if (error) {
return; // handle error
}
const output = fs.createWriteStream("./sample.png");
stream.pipe(output);
});