API Gatewayを使用したAPIリクエストの連鎖
May 23, 2023
統合する必要があるAPIの数が増えるにつれて、API間のやり取りの複雑さを管理することがますます困難になります。API Gatewayを使用することで、API呼び出しのシーケンスを作成し、APIワークフローをより小さく管理しやすいステップに分解することができます。例えば、オンラインショッピングサイトで顧客が商品を検索する際、プラットフォームは商品検索APIにリクエストを送信し、その後、商品詳細APIにリクエストを送信して商品に関する詳細情報を取得することができます。この記事では、Apache APISIX API Gateway用のカスタムプラグインを作成し、順番に呼び出されるべきクライアントリクエストを処理する方法を紹介します。
学習目標
この記事を通じて以下のことを学びます:
- チェーンAPIリクエストとは何か?
- 順次API呼び出しの例。
- Apache APISIX用のカスタムパイプラインリクエストプラグインの構築方法。
- パイプラインリクエストプラグインのデモ。
チェーンAPIリクエストとは何か、そしてなぜ必要なのか?
チェーンAPIリクエスト(またはパイプラインリクエスト、順次API呼び出し)は、ソフトウェア開発において、タスクを完了するために複数のAPI呼び出しが必要な場合にAPI間のやり取りの複雑さを管理するための技術です。これは、複数のAPIリクエストを1つのリクエストにまとめてサーバーにバッチとして送信するバッチリクエスト処理に似ています。似ているように見えるかもしれませんが、パイプラインリクエストは、サーバーに1つのリクエストを送信し、定義された順序で実行される一連のAPIリクエストをトリガーするものです。シーケンス内の各APIリクエストは、リクエストとレスポンスデータを変更することができ、1つのAPIリクエストからのレスポンスは、シーケンス内の次のAPIリクエストへの入力として渡されます。パイプラインリクエストは、クライアントが特定の順序で実行される必要がある依存する一連のAPIリクエストを実行する必要がある場合に役立ちます。
パイプラインの各ステップで、次のステップに渡す前にレスポンスデータを変換または操作することができます。これは、データを正規化または変換する必要がある場合や、クライアントに返される前に機密データをフィルタリングする必要がある場合に役立ちます。また、全体的なレイテンシを削減するのにも役立ちます。例えば、1つのAPI呼び出しがレスポンスを待っている間に別のAPI呼び出しを行うことができ、ワークフローを完了するために必要な全体的な時間を短縮できます。
Apache APISIX用のカスタムパイプラインリクエストプラグイン
APIゲートウェイは、この機能を実装するのに適した場所です。なぜなら、すべてのクライアントアプリのリクエストをインターセプトし、意図した宛先に転送できるからです。私たちはApache APISIXを使用します。なぜなら、これは人気のあるオープンソースのAPIゲートウェイソリューションであり、多くの組み込みプラグインを備えているからです。ただし、現在のブログ記事を開発している時点では、APISIXはパイプラインリクエストプラグインの公式サポートを提供していませんでした。カスタムプラグイン開発の知識を活用して、同じ機能を提供する新しいプラグインを導入することにしました。GitHubには、Luaプログラミング言語で書かれたソースコードとパイプラインリクエストプラグインの説明があります。
このプラグインを使用すると、単一のクライアントリクエストを処理するために順番に呼び出されるべきアップストリームAPIのリストを指定できます。各アップストリームAPIはリクエストとレスポンスデータを変更することができ、1つのアップストリームAPIからのレスポンスは、パイプライン内の次のアップストリームAPIへの入力として渡されます。パイプラインはRoute設定で定義でき、パイプラインが実行されるべきAPI URLの順序も定義できます。
このプラグインの使用法を例で理解しましょう。2つのAPIがあるとします。1つはGET /credit_cards
リクエストを行ってクレジットカード情報を取得し、もう1つはPOST /filter
リクエストのボディに前のレスポンスデータを受け取り、クライアントに返す前に機密データ(クレジットカード番号や有効期限など)をフィルタリングします。クレジットカードAPIエンドポイントは、許可されていない関係者に公開されるべきでない機密情報を返すためです。以下の図は、全体的なデータフローを示しています:
- クライアントがAPI GatewayのクレジットカードAPIエンドポイントにリクエストを送信してすべてのクレジットカード情報を取得すると、API Gatewayはクレジットカードバックエンドサービスからクレジットカードデータを取得するリクエストを転送します。
- リクエストが成功し、クレジットカードデータが返されると、パイプラインの次のステップであるセキュリティサービスに渡されます。
- セキュリティサービスからフィルタリングされたレスポンスが受信されると、結合されたレスポンスがクライアントに返されます。
パイプラインリクエストプラグインデモ
このデモでは、GitHub上の別の準備されたデモプロジェクトを活用します。このチュートリアルで使用されるすべてのcurlコマンド例を見つけることができ、APISIXを実行し、Docker compose.ymlファイルを使用して追加の設定なしでカスタムプラグインを有効にすることができます。
前提条件
- Dockerは、コンテナ化されたetcdとAPISIXをインストールするために使用されます。
- curlは、APISIX Admin APIにリクエストを送信するために使用されます。Postmanのような簡単なツールを使用してAPIとやり取りすることもできます。
ステップ1: APISIXとetcdをインストールして実行する
プロジェクトのルートフォルダからdocker compose up
を実行することで、APISIXとetcdを簡単にインストールできます。プロジェクトをフォーク/クローンした後、docker-compose.yml
ファイルに./custom-plugins:/opt/apisix/plugins:ro
というボリュームが指定されていることに気付くかもしれません。これは、カスタムプラグイン実装を含むpipeline-request.lua
ファイルがあるローカルディレクトリ**./custom-plugins
を、Dockerコンテナ内の/opt/apisix/plugins
**パスに読み取り専用ボリュームとしてマウントします。これにより、カスタムプラグインをランタイムでAPISIXに追加できます(この設定は、DockerでAPISIXを実行する場合にのみ適用されます)。
ステップ2: パイプラインリクエストプラグインを使用して最初のRouteを作成する
APISIXが実行されたら、cURLコマンドを使用してAPISIX Admin APIの/routes
エンドポイントにHTTP PUTリクエストを送信し、URIパス/my-credit-cards
をリッスンする最初のルートを作成します。
curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/1' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: application/json' \
--data-raw '{
"uri":"/my-credit-cards",
"plugins":{
"pipeline-request":{
"nodes":[
{
"url":"https://random-data-api.com/api/v2/credit_cards"
},
{
"url":"http://127.0.0.1:9080/filter"
}
]
}
}
}'
設定の重要な部分は「plugins」セクションで、「pipeline-request」プラグインがこのAPIルートに使用されるべきであることを指定しています。プラグイン設定には「nodes」配列が含まれており、パイプラインで実行されるべきAPIリクエストのシーケンスを定義します。ここで1つまたは複数のAPIを定義できます。この場合、パイプラインは2つのノードで構成されています。最初のノードはhttps://random-data-api.com/api/v2/credit_cards APIにリクエストを送信してクレジットカードデータを取得し、2番目のノードはhttp://127.0.0.1:9080/filterのローカルAPIにリクエストを送信してクレジットカード情報から機密データをフィルタリングします。2番目のAPIは、serverless-pre-function APISIXプラグインを使用したサーバーレス関数になります。これは、最初のAPIからのレスポンスを変更するためのバックエンドサービスとして機能します。
ステップ3: サーバーレスプラグインを使用して2番目のRouteを作成する
次に、パイプライン内の/filter
エンドポイントへのリクエストを処理するID 2の新しいルートを設定します。また、serverless-pre-function APISIXの既存のプラグインを有効にし、プラグインによって実行されるべきLua関数を指定します。この関数は、前のレスポンスからリクエストボディを取得し、クレジットカード番号フィールドを置き換え、残りのレスポンスは変更せずにそのままにします。最後に、現在のレスポンスボディを変更されたリクエストボディに設定し、HTTP 200レスポンスをクライアントに返します。このスクリプトを変更して、デコードされたボディを使用してさらなる処理や検証を行うなど、ニーズに合わせてカスタマイズできます。
curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/2' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: application/json' \
--data-raw '
{
"uri": "/filter",
"plugins":{
"serverless-pre-function": {
"phase": "access",
"functions": [
"return function(conf, ctx)
local core = require(\"apisix.core\")
local cjson = require(\"cjson.safe\")
-- リクエストボディを取得
local body = core.request.get_body()
-- JSONボディをデコード
local decoded_body = cjson.decode(body)
-- クレジットカード番号を隠す
decoded_body.credit_card_number = \"****-****-****-****\"
core.response.exit(200, decoded_body);
end"
]
}
}
}'
ステップ3: セットアップをテストする
ここで、全体的な設定をテストする時が来ました。以下のcurlコマンドを使用して、エンドポイント**http://127.0.0.1:9080/my-credit-cards
**にHTTP GETリクエストを送信します。
curl http://127.0.0.1:9080/my-credit-cards
2番目のステップで設定された対応するルートは、2つのノードを持つ**pipeline-request
プラグインを使用するように設定されているため、このリクエストはパイプラインをトリガーし、https://random-data-api.com/api/v2/credit_cards
エンドポイントからクレジットカード情報を取得し、http://127.0.0.1:9080/filter
**エンドポイントを使用して機密データをフィルタリングし、変更されたレスポンスをクライアントに返します。出力を確認してください:
{
"uid":"a66239cd-960b-4e14-8d3c-a8940cedd907",
"credit_card_expiry_date":"2025-05-10",
"credit_card_type":"visa",
"credit_card_number":"****-****-****-****",
"id":2248
}
ご覧の通り、リクエストボディ(実際にはチェーン内の最初のAPI呼び出しからのレスポンス)のクレジットカード番号がアスタリスクに置き換えられています。
まとめ
これまでに、Apache APISIX API Gateway用のカスタムパイプラインリクエストプラグインを使用して、特定の順序でAPI呼び出しのシーケンスをパイプラインとして定義できることを学びました。また、この新しいプラグインを既存のプラグインと組み合わせて、APIエンドポイントの認証、セキュリティ、およびその他のAPI Gateway機能を有効にすることもできます。