【API Gateway・StepFunctions】API呼び出しドメイン(Origin)によってStepFunctions内で分岐をする
はじめに
以下の構成のように、「APIをたたくドメインによって、後続の処理を変えたい」という実装を検証したので、その方法をご紹介します。

実装方法
実装方法自体は、以下のようにいくつか選択肢があります。
- Lambda内でOriginヘッダーをチェック
- API GatewayマッピングテンプレートでOriginチェック
- フロントエンド側で呼び出し時にカスタムヘッダー追加
今回は、なるべくインフラ側で処理ができるようにしたいので、2番で実装していきます。
APIGateway
Step Functionsへの統合の仕方は割愛します。
APIを作成したら、統合リクエストマッピングテンプレートを編集していきます。
内容としては、リクエストヘッダー内のOriginの内容によって、StepFunctionsに渡すinputにskipFirstLambda:trueを付与して渡しています。
StepFunctionsではこのskipFirstLambdaの値を参照し、分岐をします。
#set($origin = $input.params('Origin'))
#set($escapedBody = $util.escapeJavaScript($input.body))
#if($origin == "https://example.com")
{
"stateMachineArn": "arn:aws:states:ap-northeast-1:●●●●●:stateMachine::●●●●●:",
"input": "{\"skipFirstLambda\": true, \"origin\": \"$origin\", \"body\": $escapedBody}"
}
#else
{
"stateMachineArn": "arn:aws:states:ap-northeast-1::●●●●●::stateMachine::●●●●●:",
"input": "{\"skipFirstLambda\": false, \"origin\": \"$origin\", \"body\": $escapedBody}"
}
#end
テスト
では、テストしてみましょう。
ヘッダーにOrigin:https://example.comを入力してテストを押します。
skipFirstLambdaがtrueになってますね。

Origin:https://stg.example.comでテストすると問題なく、falseになります。
Step Functions
続いてStep Functionsの設定をします。
以下のようなステートマシンを作成します。

{
"Comment": "A description of my state machine",
"StartAt": "Choice",
"States": {
"Choice": {
"Type": "Choice",
"Choices": [
{
"Next": "Pass",
"Condition": "{% $states.input.`skipFirstLambda` = true %}"
}
],
"Default": "Lambda Invoke-1"
},
"Pass": {
"Type": "Pass",
"Next": "Lambda Invoke2"
},
"Lambda Invoke2": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Output": "{% $states.result.Payload %}",
"Arguments": {
"FunctionName": "arn:aws:lambda:ap-northeast-1:●●●●●:function:test-lambda:$LATEST",
"Payload": "{% $states.input %}"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2,
"JitterStrategy": "FULL"
}
],
"End": true
},
"Lambda Invoke-1": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Output": "{% $states.result.Payload %}",
"Arguments": {
"FunctionName": "arn:aws:lambda:ap-northeast-1::●●●●●::function:test-lambda:$LATEST",
"Payload": "{% $states.input %}"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2,
"JitterStrategy": "FULL"
}
],
"Next": "Lambda Invoke2"
}
},
"QueryLanguage": "JSONata"
}
テスト
ではこちらもテストしていきましょう。
{
"skipFirstLambda":true
}

しっかり分岐されていますね。

falseも試してみます。
問題なさそうです。

フロント実装
各ドメインのページからテストHTMLを作成し、リクエストのテストをしてみましょう。
サンプルHTMLは以下です。
API GatewayでCORSの設定を忘れずにしておきましょう。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>API テスト</title>
</head>
<body>
<button onclick="callAPI()">API呼び出し</button>
<div id="result"></div>
<script>
async function callAPI() {
try {
const response = await fetch('APIのエンドポイント', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({test: 'test'})
});
const data = await response.text();
document.getElementById('result').innerHTML = `<pre>Status: ${response.status}\n${data}</pre>`;
} catch (error) {
document.getElementById('result').innerHTML = `<pre>Error: ${error}</pre>`;
}
}
</script>
</body>
</html>
おわりに
今回はドメインによってAPIGatewayのマッピングテンプレートを使用して、分岐をし、Step Functionsに渡すデータを整形する方法を検証してきました。
リクエストヘッダーのOriginを使えば、簡単に実装できました。
Lambdaやフロント側でコードを書かずに済むので、リソースの役割を明確に分けることができ、管理もしやすくなるのではないでしょうか。
Discussion