Step Functions データフローシミュレーターでステートの入出力設定を理解する

# はじめに

本記事はStep Functionsで提供されているデータフローシミュレーターの紹介記事のようなものです。
`InputPath`、`Parameters`、`ResultSelector`、`OutputPath`、`ResultPath`などの説明は概要程度であり、より詳しい情報は他で参照ください。

Step Functions初心者の頃はステートマシンの入出力制御つまり`InputPath`、`Parameters`、`ResultSelector`、`OutputPath`、`ResultPath`がどのような役割を果たしているのか理解に苦労しました。
以下のように丁寧にまとめてくださっている資料もありますが、実際に手を動かして確認する方が理解が早く感じます。

https://dev.classmethod.jp/articles/stepfunctions-parameters-inter-states/

ステートマシンを動かせば、入出力制御の結果を確認することができますが、以下のようなデメリットがあります。

- 処理時間が長いステートマシンの場合、確認に時間がかかり、開発効率が下がったり、コストもかかる
- 入出力制御の設定を複数定義していた場合、それぞれがどのように関連して最終的な入力、出力を生成したのかがわかりにくい

## データフローシミュレーターとは

先ほぼ書いたデメリットを解決する機能が`データフローシミュレーター`です。
これを使用することで`InputPath`、`Parameters`、`ResultSelector`、`OutputPath`、`ResultPath`の各設定をステートマシンを実行せずにシミュレーションすることができます。
それぞれの設定の適用前、適用後のデータを並べて確認することができ、設定の学習はもちろん開発する際も役に立つ機能だと思います。
ちなみに、この機能は2021年4月頃に追加されました。

https://aws.amazon.com/jp/about-aws/whats-new/2021/04/aws-step-functions-adds-new-data-flow-simulator-for-modelling-input-and-output-processing/

Step Functionsの管理コンソールに遷移していただき、左メニューの`データフローシミュレーター`を選択するとすぐに使用することができます。

![スクリーンショット 2023-08-05 19.24.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/2e6d2b02-700f-c7b9-c9ac-e7220628e7ba.png)

## シナリオ

:::note warn
注意
データフローシミュレーターを試すため冗長な設計となっております。ご了承ください。
:::

今回は架空のシナリオをベースにデータフローシミュレーターを使用してみます。
そして、ステートに設定する各入出力制御を確認してみたいと思います。
以下、シナリオです。

- S3バケットにオブジェクトをアップロードしたらステートマシンを実行する
- ステートマシンにはPassステートとS3のGetObjectステートを配置する
  - Passステートでは、S3のObject CreatedイベントのJsonがEventBridgeから渡される。Jsonを後続のGetObjectステートで使いやすいよう加工し、出力する
  - GetObjectステートでは、Passステートの出力をAPIパラメータに渡し、処理を実行する。出力は以下の形式とする

```json
{
  "name": "ファイルをアップロードしたS3バケット名",
  "key": "アップロードしたオブジェクトのキー",
  "result": {
    "file_text": "ファイル内に記載されている文字列"
  }
}
```

ステートマシンの状態は現在以下のようにしており、`InputPath`、`Parameters`、`ResultSelector`、`OutputPath`は指定していません。
処理に必要なステートをドラッグ&ドロップした直後の状態です。
データフローシミュレーターを使用し、どのような値を指定していけばいいのかTry&Errorしていきましょう。

![スクリーンショット 2023-08-05 14.56.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/6267f0a1-f6f4-7042-721a-c85117b48953.png)

## Passステート

最初にPassステートについて確認してみます。

### State Input

まず、`Stete Input`にステートの入力となるJsonを入力します。
今回は、EventBridgeのS3 Object Createdイベントが入力となります。
EventBridgeには`サンドボックス`とう機能があり、イベントパターンのテストやイベント発生時のJsonを確認することができます。

EventBridge管理コンソール左メニューの`サンドポックス`を選択し、スクショのように入力すると今回入力となるJsonのサンプルが出力されます。
これをコピーし、`State Input`に入力してください。

![screencapture-ap-northeast-1-console-aws-amazon-events-home-2023-08-05-21_24_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/2d732978-88bc-cd61-4ba3-6ddd53e1103a.png)

```json
{
  "version": "0",
  "id": "17793124-05d4-b198-2fde-7ededc63b103",
  "detail-type": "Object Created",
  "source": "aws.s3",
  "account": "123456789012",
  "time": "2021-11-12T00:00:00Z",
  "region": "ca-central-1",
  "resources": ["arn:aws:s3:::example-bucket"],
  "detail": {
    "version": "0",
    "bucket": {
      "name": "example-bucket"
    },
    "object": {
      "key": "example-key",
      "size": 5,
      "etag": "b1946ac92492d2347c6235b4d2611184",
      "version-id": "IYV3p45BT0ac8hjHg1houSdS1a.Mro8e",
      "sequencer": "00617F08299329D189"
    },
    "request-id": "N4N7GDK58NMKJ12R",
    "requester": "123456789012",
    "source-ip-address": "1.2.3.4",
    "reason": "PutObject"
  }
}
```

![スクリーンショット 2023-08-05 21.34.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/2e3c5bb1-1213-2674-fb51-d081d1d3c0e8.png)

### InputPath

続いて、`InputPath`で入力Jsonのフィルタリングを行います。
後続の`GetObject`ステートのAPIパラメータは以下であり、入力の`detail`オブジェクトのみ取得すればよさそうです。

```json
{
  "Bucket": "MyData",
  "Key": "MyData"
}
```

入力欄に`$.detail`と入力するとフィルタリング前と後の結果が出力されます。

![スクリーンショット 2023-08-05 21.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/d754df6b-1054-b665-8f51-a7eb85e7f134.png)

### Parameters

続いて、`Parameters`です。
先ほど説明した`GetObject`ステートのAPIパラメータの情報のみ取得したいので、入力欄は以下のようにします。

```json
{
  "name.$": "$.bucket.name",
  "key.$": "$.object.key"
}
```

![screencapture-ap-northeast-1-console-aws-amazon-states-home-2023-08-05-21_47_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/edb06792-3fb5-8cb6-1654-e41d08fc3384.png)

### Task Result、ResultSelector

`ResultSelector`はPassステートに設定できないため、`Task Result`、`ResultSelector`は未設定で次に進みます。

![スクリーンショット 2023-08-05 21.51.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/9f5de2ea-0dc8-3033-5c47-9a552d5ead56.png)

![スクリーンショット 2023-08-05 21.52.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/c5c812e2-5638-1bfd-7881-ab2b56c2bf38.png)

### ResultPath、OutputPath

必要な情報は前段で出力されているので`ResultPath`も今回未設定にします。
また、これ以上特に情報の追加などは必要ないため、`OutputPath`も未設定にします。

![スクリーンショット 2023-08-05 21.57.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/cd52e6a6-8d91-6ccc-d8ea-bb860b424539.png)

![スクリーンショット 2023-08-05 21.58.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/28dd71fc-c8c7-b06c-da4f-c389a71560f2.png)

### State Output

`State Output`で最終的なステートの出力を確認することができます。
想定通りであれば、今までの設定を実際のステートに反映させてください。

![スクリーンショット 2023-08-05 21.59.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/13ae1b9c-40c7-a261-410a-19b46d569efb.png)

## GetObjectステート

`GetObject`ステートも`Pass`ステートと同様の流れで確認していきます。

### State Input

`GetObject`ステートの入力は前段`Pass`ステートの出力になります。
以下のJsonを入力してください。

```json
{
  "name": "example-bucket",
  "key": "example-key"
}
```

![スクリーンショット 2023-08-05 22.18.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/fe285ffb-3726-eae8-ab6e-cd19e74db0cf.png)

### InputPath、Parameters

すでに`GetObject`ステートのAPIパラメータに指定する情報は入力Jsonに含まれているため、`InputPath`、`Parameters`の指定は不要です。

![スクリーンショット 2023-08-05 22.18.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/7302e1d8-3ab9-bc6a-f6ef-cf399bbfc76f.png)

![スクリーンショット 2023-08-05 22.18.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/9b283a82-4850-6bf4-8614-d299d89506cf.png)

### Task Result

`Task Result`は`Task`タイプのステートが実行された後に出力されるJsonを入力する箇所です。Lambda関数の戻り値（LambdaのInvokeステート）などを入力します。
どのステートがどのような形式のレスポンスを返すかは[公式ドキュメント](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html#API_GetObject_ResponseSyntax)など確認しましたが、わかりませんでした。
こちらについては一度当該ステートを実行して確かめる必要がありそうです
`GetObject`ステートの実際のレスポンスは以下になります。（一部中略）
これを`Task Result`の入力欄に貼り付けてください。

```json
{
  "AcceptRanges": "bytes",
  "ContentLength": 30,
  "ContentType": "text/plain",
  "ETag": "\"xxxxxxxxxxxxxxxxxxxxxxxx\"",
  "Body":"おはようございます！"
}
```

![a](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/ffe2d4c2-3505-89f2-43ee-94cde16134c3.png)

### ResultSelector

`ResultSelector`は`Parameters`と似ています。
`Task Result`の結果から新たな形式のJsonを構築し、`ResultPath`に渡します。
今回は以下のJsonを指定します。最終的に出力する`text`属性を持つJsonです。

```json
{
  "text.$": "$.Body"
}
```

![スクリーンショット 2023-08-05 23.06.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/2c3502b9-0a4b-ca2d-225a-2abd7852ab6f.png)

### ResultPath

`ResultPath`では、ステートの入力に`ResultSelector`の結果を追加する設定をします。
今回は`$.result`を指定します。
※本当は`name`、`key`属性と同階層に`text`を配置したかったですが、調べた限り`GetObject`ステートの後にもう一つ`Pass`ステートを追加し、Jsonを変換する処理を噛ませるようなことをしないとできなさそうです。

![スクリーンショット 2023-08-05 23.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/3c916944-137c-5a66-28e7-b24054ec6c85.png)

### OutputPath

すでに前段で想定のJsonになっているため、`OutputPath`は指定しません。

![スクリーンショット 2023-08-05 23.35.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/10363aea-35f5-3450-d0b9-16060fb5a690.png)

### State Output

出力が想定通りか確認してください。

![スクリーンショット 2023-08-05 23.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545707/296d0d22-49ec-5d19-4fe5-275ad0d3046f.png)

## おわりに

以上で説明はおわりとなります。
データフローシミュレーターの有用性をご理解いただけたら幸いです。