他のプログラミング言語の呼び出し
外部プログラムは「外部プログラムディレクトリ」に保存されたコードファイルで、javaプログラムアーカイブファイル(.jarパッケージ)や、他のプログラムのソースコードファイルが該当する。以下の拡張子のファイルをサポートしている:
java
(.jar)python
(.py)php
(.php)js
(.js)BeanShell
(.bsh)go
(.go)shell
(.sh)ruby
(.rb)lua
(.lua)
:::tip
外部プログラムは「サンドボックス環境」の外で実行され、コンピュータ上の他のプログラム、ファイル、データを操作できるアクセス権限があるため、セキュリティリスクが伴う。ユーザーは呼び出すプログラムのセキュリティを確認する必要がある。
:::
外部プログラムの呼び出し
「外部プログラムディレクトリ」は以下の方法で素早く開くことができる:
外部プログラムを呼び出す際、Apidogはサブプロセスを起動し、その中でコマンドライン実行により指定された外部プログラムを実行する。最終的にサブプロセスの標準出力(stdout)が呼び出しの結果として返される。呼び出し全体のプロセスにおいて、コアロジックはユーザーが外部プログラムで実装し、Apidogは主に以下の3つのステップを実行する:
- 提供されたパラメータに基づいてコマンド文字列を組み立てる
- コマンドを実行する
- 結果を返す
その中で、最初のステップが呼び出しの原理を理解する上で重要だ。Apidogは「コマンドプレフィックス + プログラムパス + パラメータリスト」という式でコマンドを連結する。
「コマンドプレフィックス」はプログラムファイルの拡張子から推測される。「プログラムパス」と「パラメータリスト」は両方とも呼び出し時にユーザーが提供する。
例えば:pm.execute('com.apidog.Base64EncodeDemo.jar', ['abc','bcd'])
の場合、実際に実行されるコマンドはjava -jar "com.apidog.Base64EncodeDemo.jar" "abc" "bcd"
となる。
プログラムファイルの拡張子とコマンドプレフィックスの対応表:
言語 | コマンドプレフィックス | ファイル拡張子 |
---|---|---|
Java | java -jar |
.jar |
Python | python |
.py |
PHP | php |
.php |
JavaScript | node |
.js |
BeanShell | java bsh.Interpreter |
.bsh |
Go | go run |
.go |
Shell | sh |
.sh |
Ruby | ruby |
.rb |
Lua | lua |
.lua |
Rust | cargo run |
.rs |
Python | python |
.py |
API
pm.executeAsync
filePath
string 外部プログラムのパスargs
string[] パラメータ。jarパッケージ内の特定メソッドを呼び出す場合、JSON.stringify
が変換に使用される。それ以外の場合、_string_型以外は暗黙的に_string_に変換される。options
Objectcommand
string 外部プログラムの実行コマンド。「コマンドプレフィックス」の最初の部分が実行コマンドとなる。オプション、デフォルト値は自動的に推測される(上記の「コマンドプレフィックス」表を参照)。任意のプログラムにカスタマイズ可能。cwd
string サブプロセスの作業ディレクトリ。オプション、デフォルトは「外部プログラムディレクトリ」。env
Record<string, string> サブプロセスの環境変数。オプション、デフォルトは{}
。windowsEncoding
string Windows システムで使用するエンコーディング。オプション、デフォルトは"cp936"
。className
string jarパッケージ内で呼び出すクラス名(例:"com.apidog.Utils"
)。オプション。method
string jarパッケージ内で呼び出すメソッド名(例:"add"
)。オプション(className
に値がある場合は必須)。paramTypes
string[] jarパッケージ内で呼び出すメソッドのパラメータ型(例:["int", "int"]
)。オプション、デフォルトはパラメータに基づいて自動推測される。
- 戻り値: Promise<string>
:::tip[command
パラメータの使用]
デフォルトではApidogは.py
ファイルの実行にpython
を使用する。コンピュータにpython3
がインストールされている場合、command
をpython3
に指定できる。
pm.executeAsync('./demo.py', [], { command: 'python3' }).then(res => {
console.log('結果: ', res);
});
:::
pm.execute
:::tippm.executeAsync
の使用を推奨する。詳細はコード移行手順を参照。
:::
pm.execute(filePath, args, options)
filePath
string 外部プログラムのパスargs
string[] パラメータ。jarパッケージ内の特定メソッドを呼び出す場合、JSON.stringify
が変換に使用される。それ以外の場合、_string_型以外は暗黙的に_string_に変換される。options
ObjectwindowsEncoding
string Windowsシステムで使用するエンコーディング。オプション、デフォルトは"cp936"
。className
string jarパッケージ内で呼び出すクラス名(例:"com.apidog.Utils"
)。オプション。method
string jarパッケージ内で呼び出すメソッド名(例:"add"
)。オプション(className
に値がある場合は必須)。paramTypes
string[] jarパッケージ内で呼び出すメソッドのパラメータ型(例:["int", "int"]
)。オプション、デフォルトはパラメータに基づいて自動推測される。
- 戻り値: string
実行とログ
プログラムを実行する際、実行されたコマンドがコンソールに表示される(参考用)。結果が期待通りでない場合は、そのコマンドをコピーしてShell/CMD
に貼り付けてデバッグできる。
コンソールには実行されたプロセスの「標準出力(stdout)」と「標準エラー出力(stderr)」も表示される。stdout の内容(末尾の改行文字を除く)が実行の最終結果となる。
:::tip
歴史的な理由により、pm.execute
はstderrに内容がある場合に実行が失敗したと判断する。これにより、警告やエラーメッセージを出力する一部のプログラムが失敗することがある。pm.executeAsync
では、プロセスの終了コードを使用して実行が失敗したかどうかを判断するように変更されている。
:::
外部プログラムの入出力
パラメータ
指定された外部プログラムはコマンドライン実行で動作するため、コマンドライン引数を通じてのみパラメータを取得できる。
例えば、スクリプトpm.executeAsync('add.js', [2, 3])
では、実際に実行されるコマンドはnode add.js 2 3
となる。外部スクリプトadd.jsでパラメータを取得するには:
let a = parseInt(process.argv[1]); // 2
let b = parseInt(process.argv[2]); // 3
:::tip
- コマンドライン引数の取得方法はプログラミング言語によって異なるため、対応する言語のドキュメントを参照してね。
- コマンドライン引数の型は常に_string_なので、実際の型に応じて変換する必要がある。
:::
戻り値
前述の通り、Apidogはstdoutの内容をプログラム実行の結果として使用する。そのため、stdoutに内容を出力することで結果を返すことができる。
例えば、スクリプトconst result = await pm.executeAsync('add.js', [2, 3])
では、以下のように結果を返すことができる:
console.log(parseInt(process.argv[1]) + parseInt(process.argv[2]));
:::tip
- stdoutへの出力方法はプログラミング言語によって異なるため、対応する言語のドキュメントを参照してね。
- 戻り値の型は_string_なので、実際の型に応じて変換する必要がある。
- 結果の末尾の改行文字は削除される。
- jarパッケージ内の特定メソッドを呼び出す場合、呼び出されたメソッドの戻り値が最終的な戻り値として使用される。
:::
エラーのスロー
エラーをスローすることで、現在のタスクを失敗させ、実行を停止できる。例:
throw Error("実行が失敗しました");
:::tip
- エラーのスロー方法はプログラミング言語によって異なるため、対応するドキュメントを参照してね。
- JavaScriptでは、
console.error('Error')
はエラーをスローするのではなく、単にstderrに出力するだけ。他の言語を使用する際もこの点に注意してね。
:::
デバッグ情報
pm.executeAsync
は実行の成否の判断にstderrではなく終了コードを使用するため、stderrを実行に影響を与えずにデバッグ情報の出力に使用できる。
例:
console.warn("デバッグ情報");
console.error("エラー情報");
:::tip
- このデバッグ情報の出力方法は
pm.executeAsync
でのみサポートされている。 - stderrへの出力方法はプログラミング言語によって異なるため、対応するドキュメントを参照してね。
:::
pm.executeからpm.executeAsyncへの移行
pm.executeAsync
の戻り値は_Promise_型のため、execute
を直接executeAsync
に変更することはできない。ただし、async
/await
を使用することで最小限の変更で移行できる。
:::tip
Apidogバージョン >= 2.3.24(CLIバージョン >= 1.2.38)ではトップレベルawaitをサポートしている。
:::
手順:
execute
をexecuteAsync
に変更する- 関数呼び出しの前に
await
を追加する
// 移行前
const result = pm.execute("add.js", [3, 4]);
pm.environment.set("result", result);
// 移行後
const result = await pm.executeAsync("add.js", [3, 4]);
pm.environment.set("result", result);
.jarパッケージ内の特定メソッドの呼び出し
:::tip
この機能にはApidogバージョン>= 2.1.39
が必要。内部ランタイムリフレクションを使用するSpring Bootのようなjarではなく、リフレクションで呼び出し可能なjarのみをサポートしている。
:::
デフォルトでは、jarを呼び出すとMainクラスのmainメソッドが実行される。options.className
が指定された場合、デフォルトの動作を上書きし、代わりにjar内の指定されたメソッドを呼び出す。
jarパッケージ内の特定メソッドの呼び出しは、他の外部プログラムとは異なる。Apidogは組み込みの実行プログラムを使用して、リフレクションによってjar内のメソッドを見つけて呼び出す。呼び出されたメソッドに戻り値がある場合、その値を文字列に変換して最終的な戻り値として使用する。それ以外は他の呼び出しと同様に、stdout の内容を戻り値として使用する。
例:
await pm.executeAsync('./scripts/jar-1.0-SNAPSHOT.jar', ['hello', 'world'], {
className: 'com.apidog.Test',
method: 'combine',
paramTypes: ['String', 'String']
})
実際に実行されるコマンド:
java -jar "<app-dist>/assets/JarExecuter-1.1.0-jar-with-dependencies.jar" ./scripts/jar-1.0-SNAPSHOT.jar "com.apidog.Test.combine(String,String)" "\"hello\"" "\"world\""
ここで、<app-dist>/assets/JarExecuter-1.1.0-jar-with-dependencies.jar
は組み込みの実行プログラムで、ユーザープログラム./scripts/jar-1.0-SNAPSHOT.jar
内のメソッドcom.apidog.Test.combine(String,String)
をリフレクションで見つけ、パラメータ(JSON文字列)"hello"
と"world"
で呼び出す役割を担う。
:::tipparamTypes
はオプションだ。指定しない場合、パラメータに基づいて型が自動的に推測される。整数は"int"
として、浮動小数点数は"double"
として、真偽値は"boolean"
として、文字列は"String"
として推測される。配列は最初の要素に基づいて推測される(例:[3]
は"int[]"
として、[3.14]
は"double[]"
として推測される)。
推測された型が呼び出されるメソッドの実際のパラメータ型と一致しない場合、paramTypes
を手動で指定する必要がある。paramTypes
配列でサポートされる値:"Number"
、"int"
、"Integer"
、"long"
、"Long"
、"short"
、"Short"
、"float"
、"Float"
、"double"
、"Double"
、"boolean"
、"Boolean"
、"String"
、"Number[]"
、"int[]"
、"Integer[]"
、"long[]"
、"Long[]"
、"short[]"
、"Short[]"
、"float[]"
、"Float[]"
、"double[]"
、"Double[]"
、"boolean[]"
、"Boolean[]"
、"String[]"
そのため、上記の例のparamTypes
は省略できる:
await pm.executeAsync('./scripts/jar-1.0-SNAPSHOT.jar', ['hello', 'world'], {
className: 'com.apidog.Test',
method: 'combine'
})
:::
例
1. PHPプログラム
スクリプト:
const param1 = { a: 1, b: 2 }
const resultString = await pm.executeAsync('test.php', [JSON.stringify(param1)])
const result = JSON.parse(resultString)
console.log('結果:', result) // 結果: { a: 2, b: 4 }
test.php:
<?php
$param = json_decode($argv[1]);
$result = [];
foreach($param as $key=>$value)
{
$result[$key] = $value * 2;
}
echo json_encode($result);
2. Jarプログラム
スクリプト:
const result = await pm.executeAsync('com.apidog.utils.jar', [3, 5], {
className: 'com.apidog.utils.Utils',
method: 'add',
paramTypes: ['Integer', 'Integer']
})
console.log('結果:', result) // 結果: 8
com.apidog.utils.jar:
package com.apidog.utils;
public class Utils {
public Integer add(Integer a, Integer b) {
return a + b;
}
};
よくある問題
1. 一部のプログラムではプロジェクト設定ファイルが必要で、不足するとエラーになる
RustとGo:
Rust:
could not find `Cargo.toml` in `<...>/ExternalPrograms` or any parent directory
Go:
go.mod file not found in current directory or any parent directory; see 'go help modules'
解決策:pm.executeAsyncを使用し、cwd
を指定する。
2. MacOSにはPython 3が組み込まれているがPython 2はない
pm.executeAsyncを使用し、command
を"python3"
に設定する。
3. Command xxxが見つからない
対応するプログラムをインストールし、必要なディレクトリをシステムのPATHに追加する。Java環境のインストールについてはドキュメントを参照してね。
4. 一部のWindowsシステムで外部スクリプトの呼び出しが文字化けする
windowsEncoding
を'utf-8'
に設定する
var result = pm.execute(`hello.go`, [], { windowsEncoding: 'utf-8' })