Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS step function: Adding States.Format output to input at top level

The step function receives some input and looks up a bunch more and after that I want to add the result of a States.Format function to that input at the top level. I don't know all the input when the States.Format function is run so I need to keep all that input. Also the result of the States.Format function has to be at the top level - not in a sub-object.

If I use the Pass state to add the States.Format output then

  • Result only allows literal strings so that won't work:

      Prepare Interaction:
        Type: Pass
        Result: States.Format('payment/receipt of {} made today', $.receiptValue)
        ResultPath: $.interactionText
        Next: Create Interaction
    

    when passed:

      { ..., ReceiptValue: 123, ... }
    

    produces:

      { ..., ReceiptValue: 123, ..., interactionText: "States.Format('payment/receipt of {} made today', $.receiptValue)" }
    
  • Parameters creates a key-value pair and ResultPath requires a separate key so the result is not at the top level:

      Prepare Interaction:
        Type: Pass
        Parameters:
          interactionText.$: States.Format('payment/receipt of {} made today', $.receiptValue)
        ResultPath: $.interactionText
        Next: Create Interaction
    

    when passed:

      { ..., ReceiptValue: 123, ... }
    

    produces:

      { ..., ReceiptValue: 123, ..., interactionText: { interactionText: "payment/receipt of 123 made today" }}
    
  • Even if you grab all the input with Parameters there is no way to add an item to it:

      Prepare Interaction:
        Type: Pass
        Parameters:
          Payload.$: $
          Payload.interactionText.$: States.Format('payment/receipt of {} made today', $.receiptValue)
        OutputPath: $.Payload
        Next: Create Interaction
    

    when passed:

      { ..., ReceiptValue: 123, ... }
    

    produces:

      { ..., ReceiptValue: 123, ..., "Payload.interactionText": "payment/receipt of 123 made today" }
    

There is no way to remove the key from Parameters and just using ResultPath: $ doesn't keep the input. Is there any way to get a step function to produce

{ ..., ReceiptValue: 123, ..., interactionText: "payment/receipt of 123 made today" }

either using a Pass state or some other method that doesn't call a lambda?

Here is the entire step function:

  StateMachine:
    definition:
      StartAt: Retrieve Customer Profile
      States:
        Retrieve Customer Profile:
          Type: Task
          Resource: arn:aws:states:::lambda:invoke
          OutputPath: $.Payload
          Parameters:
            Payload.$: $
            FunctionName: !GetAtt RetrieveCustomerProfile.Arn
          Next: Prepare Interaction
        Prepare Interaction:
          Type: Pass
          OutputPath: $.Payload
          Parameters:
            Payload.$: $
            Payload.interactionText.$: States.Format('payment/receipt of {} made today by {}', $.receiptValue, $.phoneNumber)
          Next: Create Interaction
        Create Interaction:
          Type: Task
          Resource: arn:aws:states:::lambda:invoke
          OutputPath: $.Payload
          Parameters:
            Payload.$: $
            FunctionName: !GetAtt CreateInteraction.Arn
          Next: End
        End:
          Type: Succeed
like image 690
Jerry Jeremiah Avatar asked Jan 26 '26 04:01

Jerry Jeremiah


1 Answers

You probably want to use the States.JsonMerge intrinsic function for this. The example below shows how to this with a series of Pass States.

{
  "Comment": "An example to demonstrate merging keys into a single object",
  "StartAt": "Simulate Function Output",
  "States": {
    "Simulate Function Output": {
      "Type": "Pass",
      "Result": {
        "receiptValue": 25,
        "otherValue1": "some string",
        "otherValue2": "some other string"
      },
      "Next": "Augment"
    },
    "Augment": {
      "Type": "Pass",
      "Parameters": {
        "origional.$": "$",
        "new": {
          "interactionText.$": "States.Format('payment/receipt of {} made today', $.receiptValue)"
        }
      },
      "Next": "Merge"
    },
    "Merge": {
      "Type": "Pass",
      "End": true,
      "Parameters": {
        "merged.$": "States.JsonMerge($.origional, $.new, false)"
      },
      "OutputPath": "$.merged"
    }
  }
}

For your specific example though, you shouldn't need to have any Pass states. Imagine you have a function called myFirstFunction that returns this as a response. Then you want to pass the merged object to mySecondFunction.

{
  "receiptValue": 25,
  "otherValue1": "some string",
  "otherValue2": "some other string"
}

This is how you could do it without needing a Pass state.

{
  "Comment": "A description of my state machine",
  "StartAt": "Lambda Function 1",
  "States": {
    "Lambda Function 1": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "myFirstFunction"
      },
      "ResultSelector": {
        "raw.$": "$.Payload",
        "extra": {
          "interactionText.$": "States.Format('payment/receipt of {} made today', $.Payload.receiptValue)"
        }
      },
      "Next": "Lambda Function 2"
    },
    "Lambda Function 2": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "OutputPath": "$.Payload",
      "Parameters": {
        "Payload.$": "States.JsonMerge($.raw, $.extra, false)",
        "FunctionName": "mySecondFunction"
      },
      "End": true
    }
  }
}

You will see that I use ResultSelector to do the augmentation before returning the result from the first Lambda function. Then I use States.JsonMerge to merge before sending to the second function.

The second function will then get the following, which I think is what you wanted:

{
  "receiptValue": 25,
  "otherValue2": "some other string",
  "otherValue1": "some string",
  "interactionText": "payment/receipt of 25 made today"
}
like image 176
Justin Callison Avatar answered Jan 28 '26 20:01

Justin Callison



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!