The version of the NGINX JavaScript moduleのうち、NGINX Plus R15とともにリリースされたバージョンでは、サブリクエストを発行できるようになりました。つまり、JavaScriptコードからリクエストを開始できます。これにより、まったく新しいさまざまなユースケースに対応できます。
こうしたユースケースの1つがAPIリクエストのバッチ処理です。クライアントからの1つのAPIリクエストを一連のバックエンドサーバーへの複数のAPIリクエストに変換し、それぞれのレスポンスを集約して、1つのレスポンスとしてクライアントに返します。このブログでは、eコマースサイトを例に説明します。クライアントが特定の商品に関する情報をリクエストすると、カタログ、在庫、カスタマーレビューという3つのバックエンドサービスにサブリクエストが送信されます。
この記事では、NGINX Plus R15 announcementで紹介したサブリクエストの例を発展させます。この例では、サブリクエストを使用して同じリクエストを2台のバックエンドサーバーに送信し、最初のレスポンスのみをクライアントに返す方法を示しています。
[編集者注 – この記事は、NGINX JavaScriptモジュールのユースケースを紹介する一連の記事の1つです。完全な一覧については、「NGINX JavaScriptモジュールのユースケース」をご覧ください。
この記事は、 js_importディレクティブを使用するように更新されています。このディレクティブは、NGINX Plus R23以降でjs_includeディレクティブに代わるものです。詳細については、NGINX JavaScript moduleのリファレンスドキュメントを参照してください。Example Configurationセクションでは、NGINX設定ファイルとJavaScriptファイルの正しい構文を示しています。]
はじめに
この記事では、シンプルでわかりやすく、実際に動作するAPIリクエストのバッチ処理例を紹介します。これらの例は、以下の要件をすべて満たしています。
- すべてのリクエストでHTTP
GETメソッドを使用します。 - すべてのレスポンスはJSON形式です。
- 2種類の形式のAPIリクエストがサポートされています。どちらの形式でも、クエリ文字列に追加の引数を指定できることに注意してください。
- APIプログラムへの引数は、URIの最後の要素です。これを「最終要素リクエスト形式」と呼びます。この例では、クライアントから/batch-api/product/14286へのリクエストを受けると、/myapi/catalog/14286、/myapi/inventory/14286、および/myapi/review/14286へのリクエストが生成されます。
- 引数はURIのクエリ文字列で指定されます。これを「クエリ文字列リクエスト形式」と呼びます。この例では、/batch-api2/product?item=14286へのリクエストによって、/myapi/catalog.php?item=14286、/myapi/inventory.php?item=14286、および/myapi/review.php?item=14286へのリクエストが生成されます。
- クライアントリクエストによってトリガーされるサブリクエストのセットは動的に構成できます。つまり、NGINX Plusの構成を手動で編集して再読み込みすることなく変更できます。
- バックエンドサーバーへのAPIリクエストは、それぞれ独立しています。
ソリューションの概要
このソリューションでは、NGINX JavaScriptの新しいサブリクエスト機能に加えて、NGINX Plusの「キー・バリューストア」機能を利用しており、「NGINX Plus API」で設定を動的に変更できます。
以下の図は、サポートされている2つのリクエスト形式を示しています。
最終要素リクエスト形式:

クエリ文字列によるリクエスト形式:

どちらの例でも、クライアントはカタログ、在庫、レビューの各サービスから製品に関する情報を取得する必要があります。クライアントは、商品番号をURIの一部またはクエリ文字列として渡し、NGINX Plusに1件のリクエストを送信します。その後、3つのサービスにリクエストが送信され、各サービスからのレスポンスが集約されて、1件のレスポンスとしてクライアントに返されます。
これをNGINX Plusで動作させるには、次の2つのコンポーネントが必要です。JavaScriptプログラムとNGINX Plusの設定です。
JavaScriptプログラム
JavaScript関数batchAPI()は、クライアントリクエストごとに呼び出されます。この関数は、キー・バリューストアからAPI URIのカンマ区切りリストを取得して順に処理し、各URIに対してサブリクエストを実行するとともに、各レスポンスを処理するコールバック関数done()を指定します。末尾要素形式のリクエストでは、NGINX変数$uri_suffixに格納されたURIの最後の要素が、元のクライアントURIに含まれるその他のクエリ文字列引数とともに、各サブリクエストのクエリ文字列として渡されます。クエリ文字列形式のリクエストでは、クライアントリクエストのクエリ文字列が、各サブリクエストのクエリ文字列として渡されます。
呼び出しはキー・バリュー・ストアに記載されている順序で行われますが、非同期であるため、応答が返される順序は一定ではありません。応答は受信順に集約され、1つの応答としてクライアントに返されます。以下に、JavaScriptプログラムの最小構成版を示します。
コード例を読み込み中…
より充実したエラー処理、ログ記録、コメントを備えたJavaScriptプログラムのバージョンは、GitHub Gistリポジトリで「batch-api.js」として公開されています。
最小限のNGINX Plus構成
以下のNGINX Plus構成では、アップストリームサーバーのグループを使用して、前述の2つのリクエスト形式を実装します。簡潔にするため、この構成では、アップストリームサーバーが/myapi/service/item#形式の呼び出し(最終要素形式)を/myapi/service.php/?item=item#(クエリ文字列形式)に変換できることを前提としています。これは、サンプルのカタログ、在庫、レビューサービスで使用している言語であるPHPの「ネイティブ」URI形式です。
変換自体を実行する、より包括的なNGINX Plus構成については、以下の「URIを変換するためのNGINX構成の拡張」を参照してください。
構成ファイルをセクションごとに確認し、各部分の役割を説明します。
- インポートする:JavaScriptファイル:
コード例を読み込み中…
- APIリクエストのリストを保持するための「キー・バリュー・ストア」を定義します。URIの最後の要素は、APIプログラムに渡す引数を示します。キーでは、
$uri_prefix変数を使用して、URIの最後の/より前の部分を取得します。コード例を読み込み中…
NGINX Plus R16以降では、さらに2つのキー・バリュー機能を利用できます。キー・バリュー・ストアの同期を設定する手順については、「NGINX Plus Admin Guide」を参照してください。- キーバリューストアのエントリに有効期限を設定するには、
timeoutパラメーターをkeyval_zoneディレクティブに追加します。たとえば、バッチ処理された各URIを1日ごとに期限切れにするには、timeout=1dを追加します。 - Synchronize the key‑value store across a cluster of NGINX Plus instances, by adding the
syncパラメーターをkeyval_zoneディレクティブに追加して、NGINX Plusインスタンスのクラスター全体でキーバリューストアを同期します。この場合は、timeoutパラメーターも指定する必要があります。
- キーバリューストアのエントリに有効期限を設定するには、
- クエリ文字列で引数を識別するAPI用に、別のキーバリューストアを定義します。ここでは、キー(
$uri)がクエリ文字列を除くURI全体を取得します。コード例を読み込み中…
- 引数がURIの最後の要素となるリクエストを受け付けるAPI向けに、URIを2つの部分に分割する2つの「マップ」を定義します。変数「
$uri_prefix」は最後の/より前のURI要素を取得し、「$uri_suffix」は最後の要素を取得します。コード例を読み込み中…
- APIサーバーのアップストリームグループを定義します(ここでは、NGINX Plusとともにlocalhost上で実行されています)。
コード例を読み込み中…
- クライアントリクエストとサブリクエストを処理する仮想サーバーを定義します。
コード例を読み込み中…
- final‑element形式を使用するクライアントリクエストを処理するための「location」を定義します。この形式は、
batchAPI関数に対して、$batch_api_arg_in_uri変数をonに設定することで指定します。コード例を読み込み中…
- クエリ文字列形式を使用するクライアントリクエストを処理するlocationを定義します。この形式は、変数
batchAPI関数に対して、$batch_api_arg_in_uriをoffに設定することで指定します。コード例を読み込み中…
- サブリクエストを処理するlocationを定義します。
コード例を読み込み中…
- キーと値のストア内のデータを管理できるように、NGINX Plus APIを有効にします。
コード例を読み込み中…
完全な設定は次のとおりです。
コード例を読み込み中…
バッチAPIリクエストの設定
NGINX Plusのキー・バリューストア機能を使用して、受信したクライアントリクエストを、実行する一連のAPIリクエストにマッピングします。前のセクションの設定では、2つのリクエスト形式に対して個別のキー・バリューストアを定義しています。
- 最終要素スタイルのキーバリューストアの名前は「batch_api」で、キーには、リクエストURIの最後の「
$uri_prefix」より前の要素を取得する/変数を使用します。 - クエリ文字列形式のキー値ストアの名前は「batch_api2」で、キーは変数「
$uri」です。この変数は、クエリ文字列を除く完全なリクエストURIを取得します。
どちらのキー・バリューストアでも、各キーに関連付けられた値は、実行時に変数「$batch_api」または「$batch_api2」で使用可能になるURIのカンマ区切りリストです。
最終要素形式のリクエストでは、/batch-api/productに対するクライアントリクエストを、次の3つのサービスへのリクエストにマッピングします:/myapi/catalog、/myapi/inventory、/myapi/review。これにより、/batch-api/product/14286へのリクエストは、次のサービスへのリクエストになります:/myapi/catalog/14286、/myapi/product/14286、/myapi/review/14286。
これらのマッピングをbatch_apiキーバリューストアに追加するには、ローカルマシンで稼働しているNGINX Plusインスタンスに次のリクエストを送信します。
$ curl -iX POST -d '{"/batch-api/product":"/myapi/catalog,/myapi/inventory,/myapi/review"}' http://localhost/api/3/http/keyvals/batch_apiクエリ文字列形式のリクエストでは、/batch-api2/productに対するクライアントリクエストを、3つのサービス/myapi/catalog.php、/myapi/inventory.php、/myapi/review.phpへのリクエストにマッピングします。これにより、/batch-api2/product?item=14286へのリクエストは、/myapi/catalog?item=14286、/myapi/product?item=14286、/myapi/review?item=14286へのリクエストになります。
これらのマッピングをbatch_api2キーバリューストアに追加するには、次のリクエストを送信します。
$ curl -iX POST -d '{"/batch-api2/product":"/myapi/catalog.php,/myapi/inventory.php,/myapi/review.php"}' http://localhost/api/3/http/keyvals/batch_api2サンプルの実行
同じPHPページで、どちらのリクエスト形式によるリクエストも処理します。ここでは簡略化のため、バックエンドサーバーが最終要素形式のURI(/myapi/service/item#)をクエリ文字列形式のURI(/myapi/service.php?item=item#)に変換できるものとします。クエリ文字列形式はPHPプログラムの「ネイティブ」なURI形式であるため、変換する必要はありません。
すべてのサービスは、サービス名とitem引数を含むJSON形式のレスポンスを返します。たとえば、/myapi/catalog.php?item=14286へのリクエストに対して、catalog.phpは次のレスポンスを返します。
{"service":"Catalog","item":"14286"}これらの例で使用するPHPプログラムではレスポンスにサービス名が含まれていますが、すべてのサービスが同様とは限りません。レスポンスとその生成元のサービスを対応付けやすくするため、JavaScriptプログラムでは集約レスポンスにURIを含めています。
たとえば、/batch-api/product/14286へのリクエストに対する集約レスポンスは次のようになります(3つのコンポーネントレスポンスの順序は異なる場合があります)。
[["/myapi/review/14286",{"service":"Review","item":"14286"}],["/myapi/inventory/14286",{"service":"Inventory","item":"14286"}],["/myapi/catalog/14286",{"service":"Catalog","item":"14286"}]]URIを変換するためのNGINX Plus設定の拡張
前述のとおり、上記の最小限のNGINX Plus構成では、APIサーバーが次の形式のURIを変換できることを前提としています。/myapi/service/item# から /myapi/service.php/?item=item# への変換です。以下の変更を加えることで、この変換をNGINX Plus構成に実装することもできます。
- サブリクエストを受信する新しい「upstreamグループ」を追加します。
コード例を読み込み中…
- 新しい「仮想サーバー」を追加し、「services」アップストリームグループが受信したリクエストを待ち受けるようにします。クエリ文字列形式のリクエストを受信した場合、URIにはすでに「.php」拡張子が付いているため、そのまま「api_servers」アップストリームグループにプロキシされます。最終要素形式のリクエストを受信した場合は、URIの最後の要素を削除してクエリ文字列引数に変換するようにURIが書き換えられます:
コード例を読み込み中…
- 新しいアップストリームグループにプロキシするように、/myapiのlocationを変更します。
コード例を読み込み中…
完全な設定は次のとおりです。
コード例を読み込み中…
追加コンポーネント
サンプルのJavaScriptプログラムとNGINX Plus構成は、他の形式のAPIにも応用できます。このブログ記事の作成に使用したすべてのコンポーネントを使ってテストする場合は、PHPページを配信するためのNGINX Unit構成を含め、GitHubのGistリポジトリから入手できます。
batch-api.js
catalog.php
inventory.php
review.php
unit.config
まとめ
これらの例では、APIリクエストをバッチ処理し、集約したレスポンスをクライアントに返す方法を示します。NGINX Plusのキーバリューストアを使用すると、NGINX Plus APIを介してAPIリクエストを動的に設定できます。APIシステムの具体的な動作は多岐にわたるため、個々のAPIのニーズに合わせて、この例にはさまざまな機能強化を加えることができます。
NGINX JavaScriptのサブリクエストは、NGINX Open Sourceを使用してテストを開始できます。APIバッチ処理の例を試す場合や、キーバリューストアやNGINX Plus APIなど、NGINX Plusの機能を活用するその他のユースケースをテストする場合は、30日間の無料トライアルをお申し込みのうえ、お試しください。
著者について

関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります