スクリプトタスクから HTTP でファイルを送受信する

スクリプトタスクでは、ファイル型データ項目に格納されたファイルを HTTP で外部 API に送信したり、逆に API から取得したファイルをデータ項目に保存したりできます。この記事では、その基本的な操作を解説します。


ファイル型データ項目の読み取り

ファイル型データ項目は、engine.findDataByVarName() で QfileView オブジェクトのリストとして取得できます。

const files = engine.findDataByVarName("q_attachment");

if (files === null || files.isEmpty()) {
  throw new Error("ファイルが添付されていません");
}

// 1 件目のファイルを取得
const file = files.get(0);

engine.log("ファイル名: "    + file.getName());
engine.log("MIMEタイプ: "    + file.getContentType());
engine.log("サイズ (バイト): " + file.getLength());

QfileView で取得できる主な情報は以下のとおりです。

メソッド内容
getName()ファイル名
getContentType()MIME タイプ
getLength()ファイルサイズ(バイト)
getMalwareScanStatus()マルウェアスキャン結果

ファイルそのもののバイト列は QfileView から直接は取り出せません。アップロードや書き込みでは、後述のように QfileView オブジェクトそのものを API に渡す 形で扱います。


HTTP でファイルをアップロードする

ファイルを外部 API に multipart/form-data 形式で送信するには、.multipart(name, file) でファイルパートを追加します。第 2 引数に QfileView オブジェクトをそのまま渡す のがポイントです。

const files = engine.findDataByVarName("q_attachment");
if (files === null || files.isEmpty()) {
  throw new Error("ファイルが添付されていません");
}
const file = files.get(0);

const response = httpClient.begin()
  .multipart("file", file)                  // QfileView をそのまま渡す
  .post("https://api.example.com/upload");

const statusCode = response.getStatusCode();
if (statusCode < 200 || statusCode >= 300) {
  engine.log("エラーレスポンス: " + response.getResponseAsString());
  throw new Error("ファイルのアップロードに失敗しました。ステータスコード: " + statusCode);
}

engine.log("アップロード完了: " + response.getResponseAsString());

ファイル名や MIME タイプは QfileView が保持しているので、別途指定する必要はありません。

テキストフィールドと組み合わせる場合

.multipart(name, value)(2 引数版)でテキストパートを追加できます。同じ .multipart() メソッドで、引数の型に応じてファイル/テキストが自動的に区別されます。

const files   = engine.findDataByVarName("q_attachment");
const comment = engine.findDataByVarName("q_comment");

const file = files.get(0);

const response = httpClient.begin()
  .multipart("comment", comment)            // テキストパート
  .multipart("file",    file)               // ファイルパート
  .post("https://api.example.com/upload");

ファイルをリクエストボディとして送る

multipart/form-data ではなく、ファイルそのものをリクエストボディとして送りたい場合は .body(file) を使います。S3 への PUT など、raw バイナリ をボディに要求する API で使えます。

const files = engine.findDataByVarName("q_attachment");
const file  = files.get(0);

const response = httpClient.begin()
  .body(file)                               // ファイルをそのままボディに
  .post("https://api.example.com/upload/raw");

Content-Type は QfileView が保持している MIME タイプが自動的に使用されます。API 側で別の Content-Type を要求される場合は第 2 引数で明示できます。

.body(file, "application/octet-stream")     // Content-Type を明示

HTTP レスポンスをファイルとして保存する

外部 API から取得したバイナリデータ(PDF・画像など)をファイル型データ項目に保存するには、レスポンスのバイト列を NewQfile クラスにラップしてからデータ項目にセットします。

ポイントは 2 つ:

  1. レスポンスのバイト列は response.getResponse() で ByteArrayWrapper として取得する
  2. new NewQfile(fileName, contentType, byteArrayWrapper) でファイルオブジェクトを生成する

NewQfile は Questetra 独自のクラスで、フル修飾名は com.questetra.bpms.core.event.scripttask.NewQfile です。スクリプトから利用するには、Java.type() で参照を取得してから使うのが簡潔です。

const response = httpClient.begin()
  .get("https://api.example.com/report.pdf");

const statusCode = response.getStatusCode();
if (statusCode < 200 || statusCode >= 300) {
  engine.log("エラーレスポンス: " + response.getResponseAsString());
  throw new Error("ファイルの取得に失敗しました。ステータスコード: " + statusCode);
}

// NewQfile クラスを参照
const NewQfile = Java.type("com.questetra.bpms.core.event.scripttask.NewQfile");

// バイト列からファイルオブジェクトを生成
const newFile = new NewQfile("report.pdf", "application/pdf", response.getResponse());

// ファイル型データ項目に書き込む
const fileList = new java.util.ArrayList();
fileList.add(newFile);
engine.setDataByVarName("q_downloaded_file", fileList);

Java.type() について Java.type("クラスのフル修飾名") は、GraalJS が提供する Java クラス参照の取得記法です。返り値を一度変数(上の例では NewQfile)に受けておけば、それ以降は短い名前で繰り返し使えます。

もちろん new com.questetra.bpms.core.event.scripttask.NewQfile(...) のようにフル修飾名を直接書くこともできます(意味は同じです)。本記事ではクラス名が長く複数箇所で使うため、Java.type() で短縮する書き方を採用しています。

NewQfile のコンストラクタ 引数は ファイル名 / Content-Type / ByteArrayWrapper(または文字列)の順です。ByteArrayWrapper はスクリプト側からは新規生成できず、HTTP レスポンスからしか取り出せない 制約があるため、HTTP 経由で取得したデータをそのままファイル化する用途に向いています。


実践例:PDF を取得して添付ファイルとして保存する

注文 ID をもとに外部システムから PDF を取得し、ファイル型データ項目に格納する例です。

// 注文 ID を取得
const orderId = engine.findDataByVarName("q_order_id");
if (orderId === null) {
  throw new Error("注文 ID が入力されていません");
}

// 認証設定を取得
const setting = httpClient.findAuthSetting("受発注システム", false);

// PDF を取得
const response = httpClient.begin()
  .authSetting(setting)
  .get("https://api.example.com/orders/" + encodeURIComponent(orderId) + "/pdf");

const statusCode = response.getStatusCode();
if (statusCode < 200 || statusCode >= 300) {
  engine.log("エラーレスポンス: " + response.getResponseAsString());
  throw new Error("PDF の取得に失敗しました。ステータスコード: " + statusCode);
}

// ファイル型データ項目に保存
const NewQfile = Java.type("com.questetra.bpms.core.event.scripttask.NewQfile");
const pdfFile  = new NewQfile("order_" + orderId + ".pdf", "application/pdf", response.getResponse());

const fileList = new java.util.ArrayList();
fileList.add(pdfFile);
engine.setDataByVarName("q_order_pdf", fileList);

engine.log("PDF を保存しました: order_" + orderId + ".pdf");

設計上の注意

ファイル操作を含むスクリプトタスクでは、実行時間(最大 30 秒)に特に注意が必要です。大容量ファイルのアップロード・ダウンロードは時間がかかるため、対象ファイルのサイズを考慮して設計してください。file.getLength() で事前にサイズを確認し、想定外に大きい場合は処理をスキップする、といったガードを入れるのも有効です。


関連リファレンス

Questetra Supportをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む