skip to Main Content

I would like to create a dynamodb step using the resource arn:aws:states:::dynamodb:getItem where some attributes may not be available.

The relevant portion of my task is as follows:

"Get Config": {
  "Type": "Task",
  "Resource": "arn:aws:states:::dynamodb:getItem",
  "Next": "DummyPass",
  "Parameters": {
    "Key": {
      "pk": { "S.$": "$.someKey)" },
      "sk": { "S": "A" }
    },
    "TableName": "test_table"
  },
  "ResultPath": "$.config",
  "ResultSelector": {
    "foo.$": "$.Item.foo.S",
    "bar.$": "$.Item.bar.S"
  },
}

Within this task I am attempting to select the DynamoDB typed annotated items and flatten into a JSON structure of just the keys and values.

There appears to not be any intrinsic functions available that could achieve this.

The workaround is to create a lambda, though it defeats the purpose of services now being supported by step functions.

2

Answers


  1. Chosen as BEST ANSWER

    I've resolved this by creating a lambda that exposes jmespath that takes a Data and Expression attribute:

    const jmespath = require("jmespath");
    
    // convenience that ensures correct sync vs async lambda definition.
    const { wrappedApply } = require("./lambda-tools.js");
    
    function jmespathHandler (options) {
      return jmespath.search(options.Data, options.Expression);
    }
    
    module.exports = {
      jmespathHandler: wrappedApply(jmespathHandler)
    };
    

    Given an input of the following:

    {
      "x": {
        "foo": "FOO",
        "bar": "BAR",
      },
      "y": {
        "bat": "BAT"
      }
    }
    

    I can now call this function with a definition like:

    {
      "Type": "Task"
      "Resource": "arn:aws:states:::lambda:invoke",
      "End": true,
      "ResultSelector": {
        "FormatOutput.$": "$.Payload"
      },
      "OutputPath": "$.FormatOutput",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
        "Payload": {
          "Data.$": "States.JsonMerge($.x, $.y, false)",
          "Expression": "{Foo: foo, Bar: bar, Bat: bat, Baz: baz}"
        }
      },
    }
    

    Which will now output the following json.

    {
      "Foo": "FOO",
      "Bar": "BAR",
      "Bat": "BAT",
      "Baz": null
    }
    

    You can see here that I've renamed the keys but also included a missing key Baz that because selected will become null.

    Note that I've demonstrated using States.JsonMerge which could have been achieved within jmespath directly, however I just used this to demonstrate another tool you may find useful.

    For completeness I'm including wrappedApply here:

    function wrappedApply (action) {
      if (action.constructor.name === "AsyncFunction") {
        return action;
      }
      /* eslint consistent-return: "off" */
      return function (data, ctx, callback) {
        if (typeof callback !== "function") {
          return action(data, ctx, callback);
        }
        try {
          const res = action(data, ctx, callback);
          callback(null, res);
        } catch (e) {
          callback(e);
        }
      };
    }
    

    This can then be called to


  2. As for specifying an optional value in result selector – this is currently not natively available from step functions. You could however pass down the entire output into a choice state and condition on that optional value.

    For attempting to select the items and flattening into a JSON structure, we also do not yet support this natively, and will have to use a lambda function as you mentioned as a workaround.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search