Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use jsonPath inside array in AWS Step Functions

I am writing an AWS step function, and for one of the steps, I wish to call a lambda that accepts an array as one of the inputs. However, if I try to pass in a JsonPath into the array, I get

The value for the field 'arrayField.$' must be a STRING that contains a JSONPath but was an ARRAY

My step function definition:

{
  "StartAt": "First",
  "States": {
  "First": {
    "Type": "Pass",
    "Parameters": {
      "type": "person"
    },
    "ResultPath": "$.output",
    "Next": "Second"
  },
    "Second": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
      "Parameters": {
        "regularParameter": "some string",
        "arrayParameter.$": ["$.output.type"]
      },
      "Next": "Succeed"
    },
    "Succeed": {
      "Type": "Succeed"
    }
  }
}

How can I use jsonPath inside the array?

like image 885
alexgbelov Avatar asked Dec 04 '19 00:12

alexgbelov


3 Answers

Since a new release you could use the intrinsic function States.Array:

  "arrayParameter.$": "States.Array($.output.type)"

https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-intrinsic-functions.html

like image 172
Petar Butkovic Avatar answered Nov 20 '22 17:11

Petar Butkovic


As @Seth Miller mentioned JsonPath resolution within arrays doesn't work unfortunately. If the amount of values to replace in the array is small and known there's a simple workaround (in my case I needed an array of size 1).

The steps are:

  1. Initialise the array with the number of values you need;
  2. Replace each value using "ResultPath": "$.path.to.array[n]";
  3. Use "$.path.to.array" in your task.

Simple, working example:

{
  "StartAt": "First",
  "States": {
    "First": {
      "Type": "Pass",
      "Parameters": {
        "type": "person"
      },
      "ResultPath": "$.output",
      "Next": "Initialise Array"
    },
    "Initialise Array": {
      "Comment": "Add an entry for each value you intend to have in the final array, the values here don't matter.",
      "Type": "Pass",
      "Parameters": [
        0
      ],
      "ResultPath": "$.arrayParameter",
      "Next": "Fill Array"
    },
    "Fill Array": {
      "Comment": "Replace the first entry of array with parameter",
      "Type": "Pass",
      "InputPath": "$.output.type",
      "ResultPath": "$.arrayParameter[0]",
      "End": true
    }
  }
}

And to use the resulting array in your task example:

    "Second": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
      "Parameters": {
        "regularParameter": "some string",
        "arrayParameter.$": "$.arrayParameter"
      },
      "Next": "Succeed"
    },
like image 32
Dário Avatar answered Nov 20 '22 15:11

Dário


Another way to approach this is by using Parallel state that outputs an array of objects and then use jsonPath to convert it to a simple array:

{
  "StartAt": "Parallel",
  "States": {
    "Parallel": {
      "Type": "Parallel",
      "Next": "Use Array",
      "ResultPath": "$.items",
      "Branches": [
        {
          "StartAt": "CreateArray",
          "States": {
            "CreateArray": {
              "Type": "Pass",
              "Parameters": {
                "value": "your value"
              },
              "End": true
            }
          }
        }
      ]
    },
    "Use Array": {
      "Type": "Pass",
      "Parameters": {
        "items.$": "$.items[*].value"
      },
      "End": true
    }
  }
}

In this example, Parallel state outputs the following json:

{
  "items": [
    {
      "value": "your value"
    }
  ]
}

And "Use Array" state produces:

{
  "items": [
    "your value"
  ]
}
like image 1
Dmitry Kolomiets Avatar answered Nov 20 '22 16:11

Dmitry Kolomiets