flipfrogの技術ブログ

主に技術的な記事を書きます

Box APIでGuzzlehttpを使ってファイルをアップロードする方法

Box APIを使ってファイルをアップロードする方法を調べたので記事を書きます。

経緯

仕事でBox APIを使っているのですが、ファイルアップロードがうまく行かずに詰まっていました。

帰宅後に調べて解決したので記事に書きます(スッキリしました)。

APIエンドポイントのリファレンス

サンプルコード

GitHubに置いておきました。

https://github.com/flipfrog/box-api-upload-using-guzzlehttp

実装上のポイント

リファレンスにかかれている、cURLでの使い方をGuzzlehttpでどのように実装するかでした。

-F attributes='{"name":"Contract.pdf", "parent":{"id":"11446498"}}' \
-F file=@<FILE_NAME>

POSTMANを使うと、ほぼそのままリクエストパラメータを設定すればアップロードできたのですが、私は直感的にGuzzlehttpを使った実装ができませんでした。Guzzlehttpでは下記のように、multipartフォームを記述します。

    'multipart' => [
        [
            'name' => 'parent_id',
            'contents' => 0, // 0: root folder
        ],
        [
            'name' => 'file',
            'contents' => \GuzzleHttp\Psr7\Utils::tryFopen('./data/test.txt', 'rb'),
            'filename' => 'my_test.txt',
        ],
    ],

GitHub上のソース

最初のブロックの、name=parent_idの書き方は、Boxが提供するOpen API specification schemaから、openapi-generatorを使ってPHPSDKを生成したときの src/Command/Content/File/UploadFile.php ファイルに記載されていた方法を参考にしました。

2つ目のブロックのcontentsに、文字列やファイルが紐付かないstreamを指定したときには、同ブロックのfilenameを指定しないと400エラーになります。

詰まっていた理由

いくつかの理由でうまくいかずに困っていました。

アップロードするサーバーは他のエンドポイントとは別

リファレンス をよく見ていなかった自分が悪いですね。

APIを使ったファイルのアップロードに慣れていなかった

ほぼ、リファレンスに書かれている感じでPOSTMANを使うとファイルをアップロードできますが、Guzzlehttpを使って同じことをやろうとするとうまく行かない。というか、その方法が分からなかった。

下図はPOSTMANでのリクエストパラメータ設定です。 POSTMANでのリクエストの設定

情報が少ない

ネットで検索すると、同じような質問が幾つかありましたが、どれも解決に至っていませんでした。 Box公式のSDKが無く、個人的に作成されたものをGitHubで見たのですが、使うGuzzlehttpのバージョンが4.xと古く、最新の7.xでは参考になりませんでした。

追記

記事を書いたあとに情報を見つけたのですが、multipartブロックを下記のように書けば直感的になるようです。

    'multipart' => [
        [
            'name' => 'attributes',
            'contents' => json_encode([
                'name' => 'my_test.txt',
                'parent' => ['id' => 0],
            ]),
        ],
        [
            'name' => 'file',
            'contents' => \GuzzleHttp\Psr7\Utils::tryFopen('./data/test.txt', 'rb'),
            'filename' => 'my_test.txt', // optional to specify file name on box
        ],
    ],

Boxに作成されるファイルのファイル名は、1つ目のブロックのJSON内のname属性が優先して採用されるようです。

出典: https://support.box.com/hc/ja/community/posts/5289184800019-API-upload-did-not-contain-a-file-part