Search code examples
aws-lambdaaws-step-functions

In AWS Step Functions, how can I pass numbers to a Map iterator Lambda?


I currently have 2 Lambda functions in a Step Function. One always returns an array of numbers:

export const handler = async(event) => {
    const response = {
        statusCode: 200,
        body: [1, 2, 3]
    };
    return response;
};

The number elements are passed to a Map state, where an iterator function adds 1 to the input:

export const handler = async(event) => {
    const response = {
        statusCode: 200,
        body: event + 1,
    };
    return response;
};

I have set up a Step Function to run the 1st function and then run the 2nd function on each element of the output array:

{
  "StartAt": "return array",
  "States": {
    "return array": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "OutputPath": "$.Payload",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "...return-array:$LATEST"
      },
      "Retry": [
        ...
      ],
      "Next": "Map"
    },
    "Map": {
      "Type": "Map",
      "ItemProcessor": {
        "ProcessorConfig": {
          "Mode": "INLINE"
        },
        "StartAt": "add",
        "States": {
          "add": {
            "Type": "Task",
            "Resource": "arn:aws:states:::lambda:invoke",
            "OutputPath": "$.Payload",
            "Parameters": {
              "Payload.$": "$",
              "FunctionName": "...add:$LATEST"
            },
            "Retry": [
              ...
            ],
            "End": true
          }
        }
      },
      "End": true,
      "ItemsPath": "$.body"
    }
  }
}

However, I'm getting an error:

An error occurred while executing the state 'add' (entered at the event id #12). The Parameters '{"FunctionName":"...add:$LATEST","Payload":1}' could not be used to start the Task: [The value for the field 'Payload' must be a STRING]

It looks like the fix should be easy enough but I can't seem to figure out how to convert each element of [1, 2, 3] to a string before passing it to the next step.


Solution

  • As you discovered, your Map state passes number scalars to each iteration, but the Payload expects key-values or a string.

    Convert the number payload (at path $) to a string with the JsonToString intrinsic function in the add Lambda task's parameters:

     "add": {
        "Parameters": {
            "Payload.$": "States.JsonToString($)",
            "FunctionName": "...add:$LATEST"
        }
        ...
     }
    

    Your Lambda now receives a stringified number as its event. Modify your add handler code accordingly: body: parseInt(event,10) + 1 to convert the event back to a number.


    Alternatively, you could replace your add Lambda task with a Pass state as the Map's iterator. The trick is another intrinsic function, MathAdd. MathAdd accepts two numbers, so there's no type conversion hassle:

    "Add": {
      "Type": "Pass",
      "Parameters": {
        "add.$": "States.MathAdd($, 1)"
      },
      "OutputPath": "$.add",
      "Next": "AnotherTask"
    },