質問

投稿者:i
登録日:2025年4月16日(水)

レコード一括出力について

レコード一括出力APIについて質問です。 画面表示時に「レコード一括出力依頼の作成」を実行し、その後、画面上の実行ボタンを押下して「レコード一括出力依頼を取得」を実行し、ダウンロード用のURLを取得する仕組みを開発しております。 この時、「レコード一括出力依頼を取得」の実行結果に含まれるstatusが"waiting"となってしまい、期待通りの動作を確認することができません。 実行ボタンではなく、画面表示時に「レコード一括出力依頼の作成」と「レコード一括出力依頼を取得」を連続で実行した場合も同様の結果となりました。 ただし、SPIRAL上ではなく、GoogleのTalend API Testerで実行した場合はstatusが"succeeded"となり、ダウンロード用のURLが取得できております。 APIの記述は、下記のサンプルコードを参考にしております。 https://knowledge.spirers.jp/article/development/detail/6117 上記について、解決策がありましたらご教示いただけますと幸いです。

PHP 1/3
<?php

//------------------------------
// 設定値
//------------------------------
define("API_URL", "https://api.spiral-platform.com/v1");
define("API_KEY", "xxx");
define("APP_ROLE", "");
define("DB_ID", "xxx");
define("APP_ID", "xxx");

//------------------------------
// レコード一括出力依頼の作成
//------------------------------
$commonBase = CommonBase::getInstance();

// 出力依頼するファイルの設定
$body = array(
	// "fileName" => "ファイル名",
	"fileFormat" => "csv",
    "characterCode" => "utf-8WithBOM",
    "hasHeader" => "true",
    "headerType" => "displayName",
    // "sort" => "データ行ソート",
    // "where" => "レコード抽出条件",
    "fields" => array(
        array("field" => "_id"),
        array("field" => "_createdAt"),
        array("field" => "_updatedAt"),
        array("field" => 1),
        array("field" => 2),
        array("field" => 3)
    )
);
$apiResponse1 = $commonBase->apiCurlAction("POST", "/apps/". APP_ID.  "/dbs/". DB_ID. "/records/exports", $body);
$SPIRAL->setTHValue("API_RESPONSE", $apiResponse1);

//------------------------------
// レコード一括出力依頼の取得
//------------------------------
if($SPIRAL->getParams("click")) {
$commonBase = CommonBase::getInstance();

$recordExportId = $apiResponse1['id'];
$apiResponse2 = $commonBase->apiCurlAction("GET", "/apps/". APP_ID.  "/dbs/". DB_ID. "/records/exports/". $recordExportId);
$SPIRAL->setTHValue("API_RESPONSE", $apiResponse2);
}
PHP 2/3
//------------------------------
// 共通モジュール
//------------------------------
class CommonBase {
    /**
     * シングルトンインスタンス
     * @var UserManager
     */
    protected static $singleton;

    public function __construct() {
        if (self::$singleton) {
            throw new Exception('must be singleton');
        }
        self::$singleton = $this;
    }
    /**
     * シングルトンインスタンスを返す
     * @return UserManager
     */
    public static function getInstance() {
        if (!self::$singleton) {
            return new CommonBase();
        } else {
            return self::$singleton;
        }
    }
PHP 3/3
    /**
     * V2用 API送信ロジック
     * @return Result
     */
    function apiCurlAction($method, $addUrlPass, $data = null, $multiPart = null, $jsonDecode = null) {
        $header = array(
            "Authorization:Bearer ". API_KEY,
            "X-Spiral-Api-Version: 1.1",
        );
        if($multiPart) {
            $header = array_merge($header, array($multiPart));
        } else {
            $header = array_merge($header, array("Content-Type:application/json"));
        }
        if(APP_ROLE){
			$header = array_merge($header, array("X-Spiral-App-Role: ".APP_ROLE));
		}
        // curl
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_URL, API_URL. $addUrlPass);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        if ($method == "POST") {
            if ($multiPart) {
                curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            } else {
                curl_setopt($curl, CURLOPT_POSTFIELDS , json_encode($data));
            }
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        }
        if ($method == "PATCH") {
            curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        }
        if ($method == "DELETE") {
            curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        }
        $response = curl_exec($curl);
        if (curl_errno($curl)) echo curl_error($curl);
        curl_close($curl);
        if($jsonDecode){
			return $response;
		}else{
            return json_decode($response, true);
		}
    }
}

?>
更新日:2025年4月18日(金)

コメント

  • ※入力できる文字数の都合上、2つに分けて回答いたします 恐れ入りますが、statusが「succeeded」になる前に出力依頼を取得するAPIを実行しても、ダウンロード用のURLを取得することができません。 出力依頼のstatusが「succeeded」になるまで待つ必要がございますが、そこまでに時間がかかっている可能性がございます。 スパイラル内でPHPを実行している場合は、タイムアウトしていないかご確認ください。 PHP実行アクションでの実行の場合は、通知メールの設定を変更することで、エラー発生時等の通知を受け取ることができます。 ▼通知メール設定 https://support.spiral-platform.com/function/function-user-setting/4181.html また、実行に時間がかかっている場合には、処理を分けて実行することをご検討いただけますと幸いです。 ■対処方法案1 1)「レコード一括出力依頼を作成」APIで依頼を作成して「一括出力依頼ID」を受け取る 2)「レコード一括出力依頼一覧を取得」APIで1)の「一括出力依頼ID」のステータスを確認して、「レコード一括出力依頼を取得」APIを実行する

    • いいね
    2025年4月16日(水)
  • ■対処方法案2 1)ダウンロードページ:出力依頼時に、非同期でwhereを指定して別ページにリクエスト 2)別ページ:リクエストを受けたページで、「レコード一括出力依頼を作成」のAPIを実行し、依頼成功のレスポンス 3)ダウンロードページ:レスポンスを受けたページで一定時間ごとに別ページに非同期通信を実行し、 「レコード一括出力依頼を取得」のAPIでステータスを確認(失敗時は繰り返し) 4)別ページ:ステータス確認し、「succeeded」の場合に受け取ったファイルURLを、ダウンロードページにレスポンス 5)ダウンロードページ:受け取ったファイルURLを設定したダウンロードボタンを表示 ※注意事項 レコード一括出力が成功になるまで、非同期処理で確認する必要があるため、 設定時間によってはAPIの処理が増えます。 負荷状況によっては遅延が発生する可能性があります。 また、「レコード一括出力依頼を作成」依頼後の離脱や複数人での依頼など、非機能面を考慮いただきますようお願いします。 注意事項を踏まえて、対応についてご検討いただけますでしょうか。

    • いいね
    2025年4月16日(水)
  • i

    ご回答いただきありがとうございます。 URLの取得について、対処方法案1を参考に解決することができました。 続けて、初歩的な質問となりますが、ダウンロードの手順についてお伺いしたいです。 APIで取得したURLをThymeleafでbodyに渡し、aタグにURLを埋め込んでダウンロードを試みたところ、アクセストークンが必要という旨のエラーが返されました。恐らく、Authorizationヘッダの設定が必要であると認識しておりますが、設定方法が分かっておりません。 APIの共通モジュールの "Authorization:Bearer ". API_KEY とは別に設定が必要なのでしょうか?

    • いいね
    2025年4月17日(木)
  • ご確認いただきましてありがとうございます。 CSVのダウンロードについてご案内します。 ■CSVダウンロードの仕組みについて レコード一括出力依頼のstatusが「succeeded」となった後に取得できるダウンロード用URLは、APIキーによる認証が必要なエンドポイントとなっております。 そのため、このURLをそのままThymeleafでHTMLのaタグに埋め込んでフロント側から直接ダウンロードを行うことはできません。 (※APIキーがフロントに露出してしまうため、セキュリティ上の問題が生じます) ■対応方法(サーバーサイドでのダウンロード処理) 以下のように、PHP側で該当URLからCSVデータを取得し、フロントにデータとして渡す方法を推奨いたします。 ※後述のPHPをご参照ください。 このようにして取得した$fileDataには、CSVファイルの中身(文字列)が格納されます。 ■フロントへの渡し方 サーバー側で取得したCSVの中身を、Thymeleafを通じてJSへ渡し、JavaScriptでBlob化してダウンロードさせるように実装できます。 ■注意点 以下の手順: 4)別ページ:ステータス確認し、「succeeded」の場合に受け取ったファイルURLを、ダウンロードページにレスポンス 5)ダウンロードページ:受け取ったファイルURLを設定したダウンロードボタンを表示 こちらのフローについては、実際には一度PHP側でCSVデータを取得したうえで、ファイルの中身をダウンロードページに渡す必要があります。 ■別案:DLリンク生成方式(ログ用途) 別の方法として「DLリクエストごとに一時テーブルにログをインサートし、サーバー側で生成した一時DLリンクを表示する」という方法もございます。 ※ただし、この方式はDLボタンの連打などによりファイル容量やDBレコードが圧迫される懸念があるため、運用面での考慮が必要となります。 ※PHPの実行時間には制限がございますので、併せてご注意ください。 ご参考になれば幸いです。 引き続きご不明点があれば、お気軽にご質問ください。

    ■対応方法(サーバーサイドでのダウンロード処理):PHP
    $url = '<<APIレスポンスで取得したダウンロード用URL>>';
    $fileData = simpleApiGetWithApiKey($url);
    function simpleApiGetWithApiKey($url) {
       $header = array(
           "Authorization:Bearer " . API_KEY
       );
       $curl = curl_init();
       curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
       curl_setopt($curl, CURLOPT_URL, $url);
       curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
       curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
       curl_setopt($curl, CURLOPT_ENCODING, '');
       $response = curl_exec($curl);
       if (curl_errno($curl)) {
           $response = curl_error($curl);
       }
       curl_close($curl);
       return mb_convert_encoding($response, 'UTF-8', 'auto');
    }
    • いいね
    2025年4月18日(金)
あなたもログインして、
回答してみませんか?