StepFunctionsを使っていて, まだLambda経由でリソース操作していませんか?

# はじめに

案外見るんですよね, こういった構成.

![stepfunctions (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/f4086eac-e1ec-4f93-3e78-7bc4900cfc3b.png)

しかし, StepFunctionsは直接リソース操作できる対象が多くあります.

ここではDynamoDBだけ紹介しますが, ほかも使い方は似たようなものなのでWorkflow Studioを開いて確認してください.

## DynamoDBに対してできる操作

* GetItem
* PutItem
* UpdateItem
* DeleteItem

いずれも1項目を操作する系です. もし複数項目の更新等が必要な場合, Mapを使うと良いです.

![スクリーンショット 2021-07-15 103304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/c2f0f546-9da0-ec3d-abfa-0974a7774f10.png)

## できない操作

* query
* scan
* トランザクション

特にqueryはできるようになってほしいところですが, 機能追加を待ちましょう.

## 使ってみる

Workflow Studioで操作すると楽です.

![スクリーンショット 2021-07-15 113054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/8efdeb6c-034b-efea-362c-1ad2f5920966.png)

わかりやすい! 1つ1つを説明しなくても触ればわかります.

Workflow Studioはこの記事を書く1ヶ月前くらいに実装されたもので, このおかげでどのようなものがStepFunctionsから直接操作できるかわかりやすくなっています. ただ, これで全ての機能と設定が組めるというわけではないので, 設定内容によっては普通にJSONを直接触る必要があります.

DynamoDBでPutItemするときのJSONはこう

```json
    "PutItemxxxxx": {
      "Comment": "DynamoDBにxxxxxを保存",
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:putItem",
      "Parameters": {
        "TableName": "SampleTable",
        "Item": {
          "Attribute1": {
            "S.$": "$.GetValue.Payload.xxxxx"
          },
          "CreatedAt": {
            "S.$": "$.GetDate.Payload.Date"
          }
        }
      },
      "InputPath": "$",
      "ResultSelector": {}
      "OutputPath": "$",
      "Next": "Parallelxxxxxx"
    }
```

PutItemだと出力結果は大したものがなく, 通信の情報くらいしかないのでResultSelectorで全部落としてしまって良いと思います. 失敗したならエラーがCloudWatchに出力されるので, ますます不要です.

## 利点

### パッと見わかりやすい

Workflow Studioから, パッと見で何のリソースを操作しているのかがわかります.

Lambda経由でDynamoDBを操作した場合
![スクリーンショット 2021-07-15 115016.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/4119612e-6fdf-738f-02c5-8c47744bdc49.png)

StepFunctionsからDynamoDBを操作した場合
![スクリーンショット 2021-07-15 114935.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/f7c7c3c6-ee8d-19ce-851d-697878640b17.png)

### ロジックを分解すると再試行処理やエラー処理を組みやすい

DynamoDBのCRUDは, キャパシティを超えたりなどでエラーになる場合があります.

エラー時は再試行処理を書いたりするわけですが, ロジックをStepFunctions側で作ることでリソースの操作をStateMachine側に外出しでき, エラー処理が容易になります.

```json
    "PutItemxxxxx": {
      "Comment": "DynamoDBにxxxxxを保存",
      "Type": "Task",
      "Resource": "arn:aws:states:::dynamodb:putItem",
      "Parameters": {
        "TableName": "SampleTable",
        "Item": {
          "Attribute1": {
            "S.$": "$.GetValue.Payload.xxxxx"
          },
          "CreatedAt": {
            "S.$": "$.GetDate.Payload.Date"
          }
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 14,
          "Comment": "失敗時の再試行"
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "FailState"
        }
      ],
      "InputPath": "$",
      "ResultSelector": {}
      "OutputPath": "$",
      "Next": "Parallelxxxxxx"
    }
```

![スクリーンショット 2021-07-15 121027.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/d9f664c1-084b-6376-1342-113aecb21e47.png)

何のエラーで, 何秒ごとに, 再試行のたびにどれだけ間隔を引き伸ばしながら最大何回再試行するか, 設定を書くだけです. 今まではwhileしたりforしたりbreakしたりしていましたが, その必要はなくなりました.

今回の構成の例では, やろうと思えば1つのLambdaだけで処理できます. しかし, エラー落ちは網羅できていて必要ならロールバックをかけられているのか, 失敗時に再試行をすべきところは網羅できているか, いつどのリソースを操作しているのかなど, すぐに判断するのは困難です.

ちなみにJSONはWorkflow Studioが勝手に作ってくれます. CFnからリソースを`${SampleTable}`みたいに指定してとかであれば少し修正が必要ですが, 一から書くよりは遥かに楽なのでコピペしていくと早いです.

## おわりに

ほぼ全て, 新しいWorkflow Studioのおかげです.

ローコード開発は, 従来の開発と感覚が全く違うので慣れるまで大変ですが, 慣れたら快適です!!!