aws-sdk-js icon indicating copy to clipboard operation
aws-sdk-js copied to clipboard

Marshalled data returned from CallAwsService DynamoDB query has incorrect casing in type names

Open Bee-Taylor opened this issue 3 years ago • 4 comments

Describe the bug

When running the step function task CallAwsService to query a database in dynamodb, the returned items have incorrect casing in type names. More specifically, "BOOL" is returned as "Bool" which means the included unmarshall function throws an error

Expected Behavior

When running CallAwsService to query a db, it should return data in the form:

{
  "Items": [
    {
      "example": {
        "BOOL": true
      }
    }
  ]
}

Current Behavior

When running CallAwsService to query a db, it returns:

{
  "Items": [
    {
      "example": {
        "Bool": true
      }
    }
  ]
}

Reproduction Steps

The following step function:

{
  "StartAt": "DBQuery",
  "States": {
    "DBQuery": {
      "End": true,
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:dynamodb:query",
      "Parameters": {
        "TableName": "{tablename}",
        "KeyConditionExpression": "#{key} = :{key}",
        "ExpressionAttributeNames": {
          "#{key}": "{key}"
        },
        "ExpressionAttributeValues": {
          ":scopeId": {
            "S.$": "$.path.{key}"
          }
        },
        "IndexName": "{indexname}"
      }
    }
  },
  "TimeoutSeconds": 300
}

Replacing tablename with an existing table, key with the partition key of a gsi, indexname with the name of a gsi on the table, giving it the necessary permissions, and running with payload:

{
  "path": {
    "{key}": "{value}"
  }
}

Possible Solution

I imagine this should be a case of changing a hardcoded value from Bool to BOOL somewhere in the codebase, but if not, if the unmarshall function was able to deal with typenames insensitive of casing, that would also fix the problem

Additional Information/Context

No response

SDK version used

Unsure, probably latest

Environment details (OS name and version, etc.)

Called from a step function

Bee-Taylor avatar Dec 01 '22 15:12 Bee-Taylor

Hey @Bee-Taylor thanks for opening this issue can you please share the code you are using and please confirm the version of the SDK as well?

ajredniwja avatar Dec 02 '22 21:12 ajredniwja

Hi, so since this is calling SDK from step functions I'm not 100% sure if this is the right repo to ask this in, feel free to send me to a different repo if not

The dynamodb query operation is called from a step function defined in CDK, like:

  return new CallAwsService(scope, `${id}-ddbQuery`, {
    service: 'DynamoDB',
    action: 'query',
    parameters: {
      TableName: table.tableName,
      ...parameters,
    },
    iamResources: [table.tableArn, ...(IndexName ? [`${table.tableArn}/index/${IndexName}`] : [])],
    iamAction: 'dynamodb:Query',
  })

Where Table is a dynamodb table, and indexname is the name of a gsi on that table

In terms of versions, these are my aws versions in package.json:

    "aws-cdk": "^2.31.2",
    "aws-cdk-lib": "^2.31.2",
    "@aws-sdk/client-dynamodb": "^3.204.0",
    "@aws-sdk/lib-dynamodb": "^3.204.0",
    "@aws-sdk/util-dynamodb": "^3.204.0",

Bee-Taylor avatar Dec 06 '22 08:12 Bee-Taylor

+1 for this, we just ran into it. Specifically when querying a DynamoDB table from the native step function action (resource arn:aws:states:::aws-sdk:dynamodb:query) we receive a marshalled DDB object in which top-level attributes are "BOOL" but any booleans nested in a map are "Bool".

We got around this by casting type/marshall attributes to uppercase in a custom implementation of the unmarshalling function.

JoeWHoward avatar Jun 07 '23 15:06 JoeWHoward

Good god this is dumb. I have to write an intermediate layer to turn Bool to BOOL and Nul to NULL. Please fix this.

Step functions have enough quirks. This one is just ridiculous.

Here is my hack to fix this:

  const cleanedPayload = JSON.stringify(payload)
    .replace(/"Nul":/g, '"NULL":')
    .replace(/"Bool":/g, '"BOOL":');
  return unmarshall(JSON.parse(cleanedPayload));

dparish avatar Mar 01 '24 21:03 dparish