はじめに
APIGatewayには、最大29秒までの実行時間制限があります。しかし、意外と簡単にその制限を超えてしまうことがあります。
最近では、申請をすればこの制限を延ばせるようですが、そもそも長時間待たせる設計は良くないと考え、下記のように非同期実行に変更しました。
本題
StepFunctionとAPIGatewayの非同期実行については、多くの情報が既にあるのでここでは詳細は割愛します。
今回は私が実践したアプローチをご紹介します。
- APIGatewayからStepFunctionを非同期で実行します。この際、実行完了を待たずに、StepFunctionの実行ARNをすぐにレスポンスとして返します。
- そのARNを使って、StepFunctionの実行が完了しているかを確認します。
StepFunctionに渡すデータの形式は決まっており、以下のような形になります。
// リクエストのマッピングテンプレート
#set($input = $input.json('$'))
{
"input": "$util.escapeJavaScript($input)",
"stateMachineArn": "実行するStepFunctionのARN"
}
$input.json
の内容をそのまま渡すだけなら簡単ですが、例えば、エンドポイントごとに固定の値を渡したい場合には少し手を加える必要があります。
私は以下のようにカスタマイズしました。
// 作成するデータ形式
{
"request": {
"headers": {値},
"body": {値}
}
}
// リクエストのマッピングテンプレート
#set($input = $input.json('$'))
{
#set($inputJson = '{"request":{"headers":{')
#foreach($headerName in $input.params().header.keySet())
#set($headerValue = $input.params().header.get($headerName))
#set($inputJson = $inputJson + '"' + $headerName + '":"' + $headerValue + '"')
#if($foreach.hasNext)
#set($inputJson = $inputJson + ',')
#end
// ここに追加すればheaderに追加可能
#end
#set($inputJson = $inputJson + '},"body":{')
#foreach($item in $input.path('$').entrySet())
#set($inputJson = $inputJson + '"' + $item.key + '":"' + $item.value + '"')
#if($foreach.hasNext)
#set($inputJson = $inputJson + ',')
#end
// ここに追加すればbodyに追加可能
#end
#set($inputJson = $inputJson + '}}}')
{
"input": "$util.escapeJavaScript($inputJson)",
"stateMachineArn": "ステップファンクションの実行ARN"
}
}
このテンプレートでやっていることはシンプルです。リクエストされたheaderとbodyをループしてJSON形式の文字列を作成し、それをエスケープしてinput
キーに入れています。
StepFunctionへのinput
は文字列である必要があるため、このようにエスケープ処理を行っています。
さいごに
似たような処理を行っている方もいますが、多くの方はmapを作成後にreplaceで=
を:
に変換していました。
(mapがkey=value
形式で出力されるため、それをkey:value
のJSON形式に変換する方法です)
しかし、この方法では、リクエスト文字列に=
が含まれている場合に意図しない変換が発生する可能性があります。
そのため、私はループを回して手動で文字列を作成する方法を選びました。
このアプローチにたどり着くまでに意外と苦労したため、メモとして残しておきます。