Apigee Edge の JavaScript ポリシーを使用すると、API プロキシフローの処理中にカスタムコードを実行できます。たとえば、JavaScript ポリシーのカスタムコードを次の目的で使用できます。
- フロー変数を取得して設定する
- カスタム ロジックを実行し、障害処理を実施する
- リクエストまたはレスポンスからデータを抽出する
- バックエンドのターゲット URL を動的に編集する
- リクエストまたはレスポンスに対して動的にヘッダーの追加または削除を行う
- JSON レスポンスを解析する
HTTP クライアント
HTTP クライアントは、JavaScript ポリシーの高度な機能です。HTTP クライアント(httpClient オブジェクト)を使用すると、1 つまたは複数のバックエンド サービスまたは外部サービスを呼び出すことができます。HTTP クライアントが特に役立つのは、複数の外部サービスを呼び出して、レスポンスを単一の API の中にマッシュアップする必要がある場合です。
httpClient オブジェクトを使用してバックエンドを呼び出す JavaScript コードの例
var headers = {'X-SOME-HEADER' : 'some value' };
var myRequest = new Request("http://www.example.com","GET",headers);
var exchange = httpClient.send(myRequest);
httpClient オブジェクトは 2 つのメソッド get と send を公開し(send は上記のサンプルコードで使用)、HTTP リクエストを実行します。どちらのメソッドも非同期的で、実際の HTTP リクエストが完了する前に exchange オブジェクトを返します。
HTTP リクエストには数秒から数分かかる場合があります。HTTP リクエストが行われた後、リクエストからのレスポンスを処理できるように、完了したタイミングを知ることが重要です。HTTP リクエストが完了したタイミングを判断する最も一般的な方法の 1 つは、exchange オブジェクトの waitForComplete() メソッドを呼び出すことです。
waitForComplete()
waitForComplete() メソッドは、HTTP リクエストが完了してレスポンス(成功 / 失敗)が返されるまで、スレッドを一時停止します。その後で、バックエンドまたは外部サービスからのレスポンスを処理できるようになります。
waitForComplete() を使用した JavaScript コードの例
var headers = {'X-SOME-HEADER' : 'some value' };
var myRequest = new Request("http://www.example.com","GET",headers);
var exchange = httpClient.send(myRequest);
// Wait for the asynchronous GET request to finish
exchange.waitForComplete();
// Get and Process the response
if (exchange.isSuccess()) {
var responseObj = exchange.getResponse().content.asJSON;
return responseObj.access_token;
} else if (exchange.isError()) {
throw new Error(exchange.getError());
}
アンチパターン
JavaScript コードで HTTP リクエストを送信した後に waitForComplete() を使用すると、パフォーマンスに影響を与えます。
HTTP リクエストの送信後に waitForComplete() を呼び出す次の JavaScript コードを考えてみましょう。
sample.js のコード
// Send the HTTP request
var exchangeObj = httpClient.get("http://example.com");
// Wait until the request is completed
exchangeObj.waitForComplete();
// Check if the request was successful
if (exchangeObj.isSuccess()) {
response = exchangeObj.getResponse();
context.setVariable('example.status', response1.status);
} else {
error = exchangeObj.getError();
context.setVariable('example.error', 'Woops: ' + error);
}
この例では
- JavaScript コードが HTTP リクエストをバックエンド API に送信します。
- 次に
waitForComplete()を呼び出して、リクエストが完了するまで実行を一時停止します。waitForComplete()API を使用すると、バックエンドがリクエストの処理を完了して応答するまで、JavaScript コードを実行しているスレッドがブロックされます。
Message Processor で JavaScript コードを同時に実行できるスレッドの数には、常に上限があります(30%)。この上限に達すると、JavaScript コードを実行できるスレッドはなくなります。そのため、JavaScript コードで waitForComplete() API を実行する同時リクエストが多すぎる場合、後続のリクエストが 500 Internal Server Error で失敗し、JavaScript ポリシーがタイムアウトする前でも「タイムアウト」エラー メッセージが表示されます。
一般に、このシナリオは、バックエンドでのリクエストの処理に時間がかかる場合や、トラフィックが多い場合に発生する可能性があります。
影響
- JavaScript コードで
waitForComplete()を実行する同時リクエストの数が事前定義された上限を超えると、API リクエストは 500 Internal Server Error で失敗し、エラー メッセージ「タイムアウト」が表示されます。 - 特定の JavaScript ポリシーの制限時間が経過していなくても JavaScript が「タイムアウト」エラーで失敗するので、問題の原因を診断しにくくなる可能性があります。
ベスト プラクティス
HTTP クライアントで callback を使用して、コールアウト コードを合理化し、パフォーマンスを改善します。また JavaScript コードで waitForComplete() を使用しないようにします。この方法により、HTTP リクエストが完了するまでの間、JavaScript を実行するスレッドがブロックされないようになります。
callback が使用されると、スレッドは JavaScript コードで HTTP コードを送信し、プールに戻ります。スレッドはブロックされなくなったので、他のリクエストを処理できます。HTTP リクエストが完了し、callback を実行する準備ができると、タスクが作成されてタスクキューに追加されます。プールのスレッドの 1 つが、タスクの優先度に基づいて callback を実行します。
httpClient で callback を使用した JavaScript コードの例
function onComplete(response,error) {
// Check if the HTTP request was successful
if (response) {
context.setVariable('example.status', response.status);
} else {
context.setVariable('example.error', 'Woops: ' + error);
}
}
// Specify the callback Function as an argument
httpClient.get("http://example.com", onComplete);