27

I have a AWS Step Function State formatted as follows:

"MyState": {
  "Type": "Task",
  "Resource": "<MyLambdaARN>",
  "ResultPath": "$.value1"
  "Next": "NextState"
}

I want to add a second value but can't find out how anywhere. None of the AWS examples display multiple ResultPath values being added to the output.

Would I just add a comma between them?

"MyState": {
  "Type": "Task",
  "Resource": "<MyLambdaARN>",
  "ResultPath": "$.value1, $.value2"
  "Next": "NextState"
}

Or is there a better way to format these?

Jake T.
  • 4,308
  • 2
  • 20
  • 48
  • For now I've decided to convert my value to a string to store an appropriate value. But I am very interested in the answer to this question. Are ResultPaths only meant to hold one value? If you use '$' it returns all values from the input, so it seems odd to me that you'd only be able to specify one. – Jake T. Jul 06 '17 at 19:31
  • 1
    The ResultPath is defining what variable to assign the results of the lambda to, not what result to return. – ivo Aug 25 '17 at 22:52
  • You can save the multiple values (when the return value is of structured format) in another variable. Check my answer on the linked question (Java implementation). – lost in binary Sep 05 '18 at 08:41

4 Answers4

46

Let's answer this straight up: you can't specify multiple ResultPath values, because it doesn't make sense. Amazon does do a pretty bad job of explaining how this works, so I understand why this is confusing.

You can, however, return multiple result values from a State in your State Machine.

General Details

The input to any State is a JSON object. The output of the State is a JSON object.

ResultPath directs the State Machine what to do with the output (result) of the State. Without specifying ResultPath, it defaults to $ which means all the input to the State is lost, replaced by the output of the State.

If you want to allow data from the input JSON to pass through your State, you specify a ResultPath to describe a property to add/overwrite on the input JSON to pass to the next State.

Your scenario

In your case, $.value1 means the output JSON of your State is the input JSON with a new/overwritten property value1 containing the output JSON of your lambda.

If you want multiple values in your output, your lambda should return a JSON object containing the multiple values, which will be the value of the value1 property.

If you don't care about allowing input values passing through your State, leave the ResultPath as the default $ by omitting it. The output JSON containing your multiple values will be the input to the next State.

Support scenario

Here's a simple State machine I use to play with the inputs and outputs:

{
  "StartAt": "State1",
  "States": {
    "State1": {
      "Type": "Pass",
      "Result": { "Value1": "Yoyo", "Value2": 1 },
      "ResultPath": "$.Result",
      "Next": "State2"
    },
    "State2": {
      "Type": "Pass",
      "Result": { "Value2": 5 },
      "ResultPath": "$.Result",
      "Next": "State3"
    },
    "State3": {
      "Type": "Pass",
      "Result": "Done",
      "End": true
    }
  }    
}

Execute this with the following input:

{
  "Input 1": 10000, 
  "Input 2": "YOLO", 
  "Input 3": true
}

Examine the inputs and outputs of each Stage. You should observe the following:

  • The input is passed all the way through, because the ResultPath always directs output to a Result property of the input.
  • The output of State1 is overwritten by the Output of State2. The net effect is Result.Value1 disappears and Result.Value2 is "updated".

Hopefully this clarifies how to use ResultPath effectively.

Zodman
  • 3,178
  • 2
  • 32
  • 38
  • 1
    I don't quite have a scenario where this makes the most sense to do in mind, but would it be possible to not specify the result path, add two new values to the input that the step function receives, and then return the whole input + my output object? – Jake T. May 10 '18 at 19:22
  • You can, but you then the step is responsible for copying the input to the output as well as doing whatever task you want it to do. This is an antipattern and will result in a brittle state machine. – Zodman May 11 '18 at 23:13
  • Found [this](https://github.com/awsdocs/aws-step-functions-developer-guide/blob/master/doc_source/input-output-resultpath.md) helpful – Vallie Oct 17 '19 at 05:11
  • When I try to implement something like your solution in my state machine, it rejects any 'custom' field as an "Unsupported Field". – A. Rick Jul 15 '21 at 16:09
3

You cannot specify several values in ResultPath, because ResultPath defines the path of your result value in the json. The close analogy for ResultPath is a return value of a function, as your step can return only 1 value it should be put into 1 node in the resulting json.

If you have an input json

{
  "myValue": "value1",
  "myArray": [1,2,3]
}

And define your ResultPath as $.myResult the overall resulting json will be

{
  "myValue": "value1",
  "myArray": [1,2,3],
  "myResult": "result"
}

Now you can truncate this json to pass only part of it to the next step in your function using OutputPath (e.g. OutputPath: "$.myResult")

InputPath and OutputPath can have several nodes in their definition, but ResultPath should always have only 1 node.

Serg
  • 86
  • 4
0

Seems like today it can be done by using ResultsSelector.

Roman Kovtuh
  • 561
  • 8
  • 14
-1

I think it would be like the following, but I haven't actually done this so I can't say for sure.

"ResultPath": {

                 "var1" : "$.value1",
                 "var2" : "$.value2"
 },

=====

After looking further into this, I am convinced that there is no direct way to do what you want to do. Here is a way that could give you the results that you want.

1) You would omit the InputPath, OutputPath, and ResultPath from your step. This would mean that all of $. would be passed in as an input to your step function and that all of the output from the lambda function would be stored as $. In the lambda function you could set the results fields to be whatever you want them to be. The lambda function must return the modified input as it output.

Itsme2003
  • 141
  • 8
  • I was considering something similar, but the original one value ResultPath doesn't show key/value pairs like that, just the reference path. I'll have to do some experimentation later and figure it out, I just changed my implementation to only depend on a single string variable rather than a few booleans so I could keep moving forward. – Jake T. Jul 07 '17 at 15:48
  • If you want to keep the original input as well, you'd typically do something like `"ResultPath": "$.mytask"` and if your lambda returned `{"value1": "foo", "value2": "bar"}`, you could access the results as `$.mytask.value1` and `$.mytask.value2`. – ivo Aug 25 '17 at 22:50
  • Have a look at [this](https://github.com/awsdocs/aws-step-functions-developer-guide/blob/master/doc_source/input-output-resultpath.md) – Vallie Oct 17 '19 at 05:11