Step Functionsの入出力処理を、TestState APIを使って確認しながら作成する

# はじめに

先日、AWS Step FunctionsにTestState APIが実装されました。

https://aws.amazon.com/jp/about-aws/whats-new/2023/11/aws-step-functions-https-endpoints-teststate-api/

これを使うと、ステートの内部の途中データが見ることができます。

今回はこれを使って、Step Functionsのわかりづらい入出力処理を確認しながらステートを作る例を記事にしました。

# 概要

- TestState APIには、Inspection levelとして、`INFO`/`DEBUG`/`TRACE`が指定できる
- `DEBUG`を使うと、データ操作の中身が確認できる
    - 各入力処理を確認することができる

Step Functions の入出力処理は、InputPath、Parameters、ResultSelector、ResultPath、OutputPathがあり、いつ動くのかは、以下のページで図示されています。

https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/concepts-input-output-filtering.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/2f661a0a-277f-4686-d903-be076bcc209b.png)



# やってみた

## 目標
以下のステートを、各入力処理を作ってみます。

1. Auto Scalingの成功したスケールアウトイベントを入力として
1. 対象のEC2インスタンスのENIの情報を取得して
1. 入力のイベントのdetailにENIのIDを追加して
1. detailのみを出力する

## ステート
単純に、DescribeNetworkInterfacesのみのステートを定義します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/59f95aaa-e711-b476-3ef3-e1cb59e601d7.png)

最終的なコードは以下になります。
```json
{
  "Comment": "ENIIDをdetailに組み込み、detailのみ抽出",
  "StartAt": "DescribeNetworkInterfaces",
  "States": {
    "DescribeNetworkInterfaces": {
      "Type": "Task",
      "Parameters": {
        "Filters": [
          {
            "Name": "attachment.instance-id",
            "Values.$": "States.Array($.EC2InstanceId)"
          }
        ]
      },
      "Resource": "arn:aws:states:::aws-sdk:ec2:describeNetworkInterfaces",
      "End": true,
      "InputPath": "$.detail",
      "ResultSelector": {
        "NetworkInterfaceIds.$": "$.NetworkInterfaces[*].NetworkInterfaceId"
      },
      "ResultPath": "$.detail.NetworkInterface",
      "OutputPath": "$.detail"
    }
  }
}
```

## 入力イベント
以下のページから、成功したスケールアウトイベントを使います。`EC2InstanceId`のみ、自分のIDに置き換えます。

https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/ec2-auto-scaling-event-reference.html#ec2-auto-scaling-successful-scaling-events

```json
{
  "version": "0",
  "id": "12345678-1234-1234-1234-123456789012",
  "detail-type": "EC2 Instance Launch Successful",
  "source": "aws.autoscaling",
  "account": "123456789012",
  "time": "yyyy-mm-ddThh:mm:ssZ",
  "region": "us-west-2",
  "resources": [
    "auto-scaling-group-arn",
    "instance-arn"
  ],
  "detail": {
    "StatusCode": "InProgress",
    "Description": "Launching a new EC2 instance: i-12345678",
    "AutoScalingGroupName": "my-asg",
    "ActivityId": "87654321-4321-4321-4321-210987654321",
    "Details": {
      "Availability Zone": "us-west-2b",
      "Subnet ID": "subnet-12345678"
    },
    "RequestId": "12345678-1234-1234-1234-123456789012",
    "StatusMessage": "",
    "EndTime": "yyyy-mm-ddThh:mm:ssZ",
    "EC2InstanceId": "i-1234567890abcdef0",
    "StartTime": "yyyy-mm-ddThh:mm:ssZ",
    "Cause": "description-text",
    "Origin": "EC2",
    "Destination": "AutoScalingGroup"
  }
}
```


## InputPath
`$.detail`を指定して、入力イベントからdetailだけを絞り込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/890e432e-e344-9db1-cd75-1ee917425559.png)

対象のステートを選択すると、右ペインの上ののほうにボタンが出てきますのでテストします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/26e0cde1-61ca-04d5-13e1-802924c026bf.png)

状態の入力に、入力イベントを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/0efb01dc-388c-b857-da53-8db0416a0e74.png)

Inspection levelをDEBUGに指定して、テストを開始します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/df3e3bdc-c44d-f831-bb80-ac95aa69f5f5.png)

右側の IO処理のタブで、途中データを見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/3b5cf991-d8af-1974-7859-1bbb97002201.png)

afterInputPathの中身を展開すると、detailが取れていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/63f16f35-00b3-c5de-c778-43e0b7d8ae40.png)

## Parameters
DescribeNetworkInterfacesのパラメータを指定します。

```json
{
  "Filters": [
    {
      "Name": "attachment.instance-id",
      "Values.$": "States.Array($.EC2InstanceId)"
    }
  ]
}
```

TestState APIを実行して、パラメーターのパスの個所が置き換わっていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/b575d6bd-20c2-7b1b-e65c-03df60b6bb4d.png)

## ResultSelector
結果からEMIのIDのみ抽出して、以下のフィールド名で取得します。
```json
{
  "NetworkInterfaceIds.$": "$.NetworkInterfaces[*].NetworkInterfaceId"
}
```

TestState APIを実行して、パス通りに取れているか確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/2ae94d54-2225-d3a2-4c57-b1f111b57101.png)


## ResultPath
抽出した結果を入力の`$.detail.NetworkInterface`に組み合わせます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/2904dc50-16ad-32b1-64b4-de590b473edf.png)

TestState APIを実行して、afterResultPathの中身で、組み合わせた結果が確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/60ae7a8f-b874-57a2-526f-ed3f6b3d6d4d.png)

## OutputPath
`$.detail`を指定して、detailだけにフィルタリングします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/3a9aebed-168c-d20e-6a13-37976a1c3833.png)

TestState APIを実行して、outputの中身がフィルタリングされていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/66d135fd-733c-9c34-6792-9930e157f867.png)

# おわりに
TestState APIを使って、Step Functionsの各入出力処理を確認しながら作ってみました。以前はパスが展開されているかわからなかったのですが、この機能を使えば途中のデータが確認できるので大変作りやすくなったと感じます。

この記事がどなたかのお役に立てれば幸いです。