AWS Step Functions から API Gateway に HTTP リクエストを送信してみた

2023.07.11

いわさです。

API Gateway で管理されるプロダクトにて、マイクロサービス的にあるサービスから別のサービスを呼び出す機会がありました。
呼び出し元のサービスはバックエンドに Step Functions を使う同期 API となっており、複数のサービスを呼び出すことを想定しています。

Step Functions の汎用的なコンポーネントで HTTP クライアント的なものは存在しないので、Lambda 関数などを経由して HTTP リクエストを送信する感じになるのかなと思ったのですが、宛先が API Gateway であれば AWS SDK 経由で Step Functions 内の 1 タスクとして実行することが出来るようだったので検証してみました。

構成としては次のように、Lambda 統合のリソースhogefugaがあり、Step Functions 統合のリソースpiyoがあります。
piyoのワークフロー内ではhogefugaを呼び出します。

今回は対象リソースが Lambda なので Step Functions から直接 Invoke も出来なくもないのですが、実際には API Gateway の統合先が ECS Fargate だったり外部の HTTP エンドポイントだったりという場合も想定しています。

API Gateway に Lambda 統合リソースを作成

次のようなほぼデフォルトの Lambda 関数を 2 つ作成し、API Gateway のリソースにそのまま Lambda プロキシモードで設定します。

index.mjs

export const handler = async(event) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('hoge!!'),
    };
    return response;
};

ステージデプロイ後、次のようにレスポンスが取得出来ることを確認しました。

% curl https://9vdm10xqkh.execute-api.ap-northeast-1.amazonaws.com/stage1/hoge
"hoge!!"
% curl https://9vdm10xqkh.execute-api.ap-northeast-1.amazonaws.com/stage1/fuga
"fuga!!!"

これは API Gateway + Lambda の一番ベーシックな構成なので特に注意する点もないかなと思います。

API Gateway から Step Functions 統合リソースを作成

API Gateway から Step Function を呼び出すパターンも実はよくあって公式ドキュメントでは次のページで紹介されています。

ここでは次のように静的な出力を行うワークフローを作成し、API Gateway にリクエストが送信されたときに実行出来るようにしてみます。

Step Functions の場合は Lambda と異なり、専用の統合機能が用意されていないので、統合タイプ「AWS サービス」からサービスとアクションを指定します。

後ほど変更しますが、まずはアクションはStartExecutionを指定してみます。

公式ドキュメントに記載の手順だと対象のステートマシンを指定しておらず、リクエストパラメータで入力する形になっています。
リソースごとに統合先を管理したいので、ここではリクエストマッピングテンプレートでリクエストボディを直接指定しました。入力パラメータは今回考慮していないので検証の範囲であればこの内容で良いと思います。

API をテスト実行してみると次のようなレスポンスが取得出来ます。
ステータスコードから成功していそうなことがわかりますが、先程ワークフローで設定した静的なレスポンスが取得出来ていません。

次のように実行されていることは確認出来るのですが、StartExecution API は非同期実行なので、結果は別途 DescribeExecution API で取得する必要があります。

同期実行させたい

今回は API Gateway から Step Functions を同期的に実行し、そのまま API Gateway でクライアントにレスポンスを行おうと考えていましたので同期実行させてみましょう。
Step Functions のワークフローには 標準 と Express の 2 種類のタイプが用意されています。

標準は非同期で利用されるものですが、長期間かけて実行することが出来ます。
一方で Express は同期でも非同期でも実行が可能で、実行時間は短いのですが今回のような同期 API のバックエンドなどでの利用も想定されています。

Express ワークフローで作成したうえで、API Gateway からは StartSyncExecution アクションを指定することで同期実行が可能です。

テスト実行してみると次のようにレスポンスを取得することが出来ました。

次のように統合レスポンスのマッピングテンプレートで Step Functions の同期実行で取得出来た結果から必要な情報だけ抜き出してみます。

良さそうですね。

実際にマッピングテンプレートを検討するにあたっては次の記事が参考になります。
次の記事では CDK のインテグレーション機能を使うことで同期 API の自動作成について紹介されていますが、自動生成されるマッピングテンプレートはこのまま参考になると思います。

Step Functions から Lambda 呼び出し

続いて本題の Step Functions から API Gateway へのリクエストを送信してみます。
先程のステートマシンを編集し、作成済みのhogeリソースを呼び出すようにしてみます。

API Gateway の Invoke API を使用します。
ヘッダーやリクエストボディなど細かくパラメータを指定することが出来るので認証トークンなども引き渡すことが出来ますね。

今回は認証なし・パラメータなしでシンプルに GET リクエストを送信するだけです。

出力を加工しない場合、次のような結果が取得されました。
ResponseBodyにアクセスできれば良さそうですね。

今回は 2 つのリソースに対して並列でリクエストを送信し、レスポンスを適当に結合してみました。
それぞれのタスクからは出力でResponseBodyを取得しています。この検証内ではエラーなどの考慮が一切されておらず単純化しているのでご注意ください。

適当な関数で出力を生成してみました。
配列に固定インデックスでアクセスしているのを見るとゾワっとしますが、検証用なので今回はこのままで行きます。

ステートマシンの編集が完了したら、クライアントから API Gateway に対してリクエストを送信してみます。

% curl https://9vdm10xqkh.execute-api.ap-northeast-1.amazonaws.com/stage1/piyo | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    59  100    59    0     0    170      0 --:--:-- --:--:-- --:--:--   172
{
  "output": {
    "fuga-result": "fuga!!!",
    "hoge-result": "hoge!!"
  }
}

良いのではないでしょうか。

さいごに

本日は AWS Step Functions から API Gateway に統合された API を実行してみました。
おまけで、Step Functions を同期実行する API Gateway リソースの作成方法も確認しました。

API Gateway に統合されていれば、Lambda などから HTTP リクエストを送信する必要が無く別のサービスへ HTTP リクエストを送信することが確認出来ました。