AWS Step FunctionsステートマシンからDynamoDBテーブルをQueryする

2021.11.01

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、AWS Step FunctionsステートマシンからDynamoDBテーブルをQueryしてみました。

やってみた

対象のDynamoDBテーブル

下記のDynamoDBテーブルをクエリ対象とします。

  • テーブル名:crews
  • PK:crewId(String)
  • GSI名:areaId-index
  • GSI-PK:areaId(String)

格納されているデータは以下となります。

ステートマシンの作成

Step Functions Workflow Studioでステートマシンを作成します。

Step Functionsのマネジメントコンソールでステートマシンの作成を開始します。

[次へ]をクリックします。

[action]をqueryで検索して[DynamoDB Query]をドラッグします。

[Query]の[設定]で、[APIパラメータ]で下記のJSONを指定します。ポイントはExpressionAttributeValuesの指定はDynamoDB Json形式とし、ExpressionAttributeNamesは通常のJson形式とすることです。(Step FunctionsでのDynamoDBテーブルのAPI操作ではDynamoDB.DocumentClient()ではなくDynamoDB()が使われるようですね。)指定したら[次へ]をクリックします。

{
  "TableName": "crews",
  "IndexName": "areaId-index",
  "ExpressionAttributeNames": {
    "#areaId": "areaId"
  },
  "ExpressionAttributeValues": {
    ":areaId": {
      "S.$": "$.areaId"
    }
  },
  "KeyConditionExpression": "#areaId = :areaId"
}

生成されたコードを確認したら[次へ]をクリックします。

生成されたコード(ステートマシン定義)は下記のようになります。

{
  "Comment": "A description of my state machine",
  "StartAt": "Query",
  "States": {
    "Query": {
      "Type": "Task",
      "End": true,
      "Parameters": {
        "TableName": "crews",
        "IndexName": "areaId-index",
        "ExpressionAttributeNames": {
          "#areaId": "areaId"
        },
        "ExpressionAttributeValues": {
          ":areaId": {
            "S.$": "$.areaId"
          }
        },
        "KeyConditionExpression": "#areaId = :areaId"
      },
      "Resource": "arn:aws:states:::aws-sdk:dynamodb:query"
    }
  }
}

ステートマシンの作成を完了します。

ステートマシンを作成できました。不足しているDynamoDBへのアクセス権限を付与するために[IAMでロールを編集]をクリックします。

今回はAWS管理ポリシーのAmazonDynamoDBReadOnlyAccessをアタッチしました。(ポリシーは必要に応じて用意してください)

動作

Step Functionsのコンソールに戻り、ステートマシンを実行します。入力はJSONを{"areaId": "<クエリしたいPK>"}のように指定します。まずareaIdがa002のアイテムを取得するクエリです。

{
  "areaId": "a002"
}

クエリが成功しました。areaIdがa002のアイテムが取得できています。

次にareaIdがa001のアイテムを取得するクエリです。

{
  "areaId": "a001"
}

クエリが成功しました。areaIdがa001のアイテムが取得できています。

ハマった箇所

ExpressionAttributeValuesの指定方法の誤り

ステートマシンの定義でExpressionAttributeValuesの指定をDynamoDB Json形式としておらずエラーとなりハマりました。

{
  "Comment": "A description of my state machine",
  "StartAt": "Query",
  "States": {
    "Query": {
      "Type": "Task",
      "End": true,
      "Parameters": {
        "TableName": "taxicrews",
        "IndexName": "areaId-index",
        "ExpressionAttributeNames": {
          "#areaId": "areaId"
        },
        "ExpressionAttributeValues": {
          ":areaId.$": "$.areaId"
        },
        "KeyConditionExpression": "#areaId = :areaId"
      },
      "Resource": "arn:aws:states:::aws-sdk:dynamodb:query"
    }
  }
}

上記定義に対して以下の入力をした場合、

{
  "areaId": "a001"
}

ステートマシンの実行が次のようなエラーとなります。

{
  "error": "States.Runtime",
  "cause": "An error occurred while executing the state 'Query' (entered at the event id #2). The Parameters '{\"TableName\":\"taxicrews\",\"IndexName\":\"areaId-index\",\"ExpressionAttributeNames\":{\"#areaId\":\"areaId\"},\"ExpressionAttributeValues\":{\":areaId\":\"a001\"},\"KeyConditionExpression\":\"#areaId = :areaId\"}' could not be used to start the Task: [Cannot construct instance of `software.amazon.awssdk.services.dynamodb.model.AttributeValue$BuilderImpl` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('a001')]"
}

ExpressionAttributeNamesの指定方法の誤り

ステートマシンの定義で逆にExpressionAttributeNamesの指定をDynamoDB Json形式としてしまった際もエラーとなりハマりました。

{
  "Comment": "A description of my state machine",
  "StartAt": "Query",
  "States": {
    "Query": {
      "Type": "Task",
      "End": true,
      "Parameters": {
        "TableName": "taxicrews",
        "IndexName": "areaId-index",
        "ExpressionAttributeNames": {
          "#areaId": {
            "S": "areaId"
          }
        },
        "ExpressionAttributeValues": {
          ":areaId": {
            "S.$": "$.areaId"
          }
        },
        "KeyConditionExpression": "#areaId = :areaId"
      },
      "Resource": "arn:aws:states:::aws-sdk:dynamodb:query"
    }
  }
}

上記定義に対して以下の入力をした場合、

{
  "areaId": "a001"
}

Taskの実行が次のようなResourceNotFoundExceptionエラーとなります。

{
  "resourceType": "aws-sdk:dynamodb",
  "resource": "query",
  "error": "DynamoDb.ResourceNotFoundException",
  "cause": "Requested resource not found (Service: DynamoDb, Status Code: 400, Request ID: c55042fb-70fa-426e-b03e-546c1b24de2f, Extended Request ID: null)"
}

おわりに

AWS Step FunctionsステートマシンからDynamoDBテーブルをQueryしてみました。

DynamoDB()のAPIを使用したクエリ操作というのをあまりやったことがなかったので結構ハマりましたが何とかできて良かったです。

参考

以上