blog top

Step Functions を API にする

私は以前、Step Functionsの機能を紹介する記事を書きました。

これは「Lambdaを使わなくても色んなことができるよ!」という趣旨の記事だったのですが、このままでは味気ないので、Step FunctionsをAPIにしていきたいと思います。

今回登場するサービスは以下の3つです。

ステートマシンを作成する

まずは土台となるステートマシンを作成していきます。

ステートマシン作成画面

設定は以下の通りです。

「標準」のワークフローは状態遷移数に応じて課金されるのですが、「Express」はリクエスト数実行時間に応じて課金されます。

つまり、ExpressワークフローはLambdaのような気持ちで使えるということです!

ワークフローの中身は、今回はシンプルに「Pass」ステートのみで構成します。

ステートマシン作成画面

Passステートの出力は、

{
  "message": "Hello, World!"
}

とします。

Passステートの出力設定

この状態でステートマシンを作成します。

(ロググループが既に存在するというエラーが出ることがあります。その場合は、画面上部「設定」からロググループ名を変更してあげます。)

IAMロールの作成

API GatewayがStep Functionsを呼び出すための権限を設定する必要があります。

まずはIAMポリシーを作成します。API GatewayがStep FunctionsのStartSyncExecutionというアクションを実行するためのポリシーを作成します。

ARNは、先ほど作成したステートマシンのARNを指定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "InvokeStepFunctions",
            "Effect": "Allow",
            "Action": "states:StartSyncExecution",
            "Resource": "<ステートマシンのARN>"
        }
    ]
}

ポリシー名はここではInvokeStepFunctionsPolicyとして作成します。

IAMポリシー作成画面

次にIAMロールを作成していきます。

次に、IAMロールの作成画面で、「カスタム信頼ポリシー」を選択します。

IAMロールの信頼ポリシー設定画面

内容は以下のようになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "InvokeStepFunctions",
            "Effect": "Allow",
            "Principal": {
                "Service": "apigateway.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

次ページの「許可ポリシー」では、先程作成したInvokeStepFunctionsPolicyを選択します。

IAMロールの許可ポリシー設定画面

ロール名はInvokeStepFunctionsRoleとし、ロールを作成します。

① API Gateway HTTP APIと統合する

それではStep FunctionsをAPI Gateway HTTP APIと統合していきます。この後に作成するREST APIよりもかなりシンプルな設定になります。

まずはAPI Gatewayのコンソールに移動し、「HTTP API」を選択します。

API Gateway HTTP APIの作成画面

API名はSampleAPIとし、「確認して作成」を押して作成します。

API Gateway HTTP APIのAPI名設定画面

次にルートの設定をします。Routes画面でGETの/を定義しましょう。

API Gateway HTTP APIのルート設定画面

次に、Step Functionsとの統合を設定します。Integrations画面で「統合を作成してアタッチ」をクリックします。

API Gateway HTTP APIの統合設定画面

以下のように設定し、作成します。

API Gateway HTTP APIの統合タイプ選択画面

作成されたら、「デフォルトのエンドポイント」を叩いてみましょう。

API Gateway HTTP APIのデフォルトエンドポイント

curlで叩くと以下のように返ってきます。少々レスポンスが大きいですが、outputの部分にHello, World!が含まれていることがわかりますね!

curlで叩いたAPI Gateway HTTP APIのレスポンス

参考までに、JavaScriptで整形するとこのように書けます。

const res = await fetch(
  "<API Gateway HTTP APIのエンドポイントURL>",
);
const data = await res.json();
const output = JSON.parse(data.output);
console.log(output);

Denoで実行してみました。良い感じですね!

TypeScriptで整形したAPI Gateway HTTP APIのレスポンス

このAPIは自身で利用する分には十分ですが、billingDetailsexecutionArnなどの情報が含まれており、外部に公開するものとしては心もとないです。

API Gateway REST APIを使うと、このレスポンスをカスタマイズすることができるので、実際にやっていきましょう。

② API Gateway REST APIと統合する

API Gatewayのコンソールに移動し、「REST API」を選択します。

API Gateway REST APIの作成画面

名前はSampleAPI2とし、APIを作成します。

API Gateway REST APIのAPI名設定画面

リソース画面で、「メソッドを作成」をクリックします。

API Gateway REST APIのメソッド作成画面

「メソッドを作成」画面では以下のように埋めます。少々細かいですが、HTTP APIと同様の設定になります。

API Gateway REST APIのメソッド作成画面

呼び出すステートマシンを指定するため、「マッピングテンプレート」を設定する必要があります。

上で作成したGETメソッドを選択し、「統合リクエスト」タブの「編集」をクリックします。

API Gateway REST APIの統合リクエスト編集画面

最下部までスクロールし、「マッピングテンプレート」を追加します。

コンテンツタイプはapplication/jsonとし、

マッピングテンプレート: 以下の内容を入力します。ステートマシンのARNは先ほど作成したものを指定してください。

{
  "input": "{}",
  "stateMachineArn": "<ステートマシンのARN>"
}

API Gateway REST APIのマッピングテンプレート設定画面

ここまででちょうどHTTP APIと同様の設定ができました。

さらにレスポンスを整形するために、次は「統合レスポンス」の「マッピングテンプレート」を設定します。

編集ボタンを押すと空のマッピングテンプレートが表示されるので、中身を以下のように入力します。

#set($resp = $util.parseJson($input.body))
$resp.output

これで、レスポンスのoutput部分のみを抽出することができます。設定されると以下のような画面になります。

API Gateway REST APIの統合レスポンスマッピングテンプレート設定後画面

最後に、APIをデプロイしましょう。画面右上の「API をデプロイ」ボタンをクリックします。

としてデプロイします。(何か設定を変更するたび、デプロイが必要です。)

API Gateway REST APIのデプロイ画面

「ステージ」画面にURLが表示されるので、これを使ってAPIを叩いてみましょう。

API Gateway REST APIのステージ画面

curlで叩くと以下のようにmessageのみが返っていますね!

curlで叩いたAPI Gateway REST APIのレスポンス

まとめ

今回はStep FunctionsのステートマシンをAPI Gatewayと統合することで、APIとして利用できるようにしました。

また、

ということがわかりました。

API Gatewayでは他にも

といった機能があるため、これらを組み合わせることで本番運用可能なAPIも構築できそうですね。