aws-cdk icon indicating copy to clipboard operation
aws-cdk copied to clipboard

events: using fromObject does not maintain keys in inputTransformer

Open kenmacf2 opened this issue 9 months ago • 1 comments

Describe the bug

creating a rule target using fromObject does not preserve the key names, but rather generates a key from the values in the input paths. using L1 CfnRule works as expected

import * as cdk from "aws-cdk-lib";
import * as events from "aws-cdk-lib/aws-events";
import * as targets from "aws-cdk-lib/aws-events-targets";
import * as sqs from "aws-cdk-lib/aws-sqs";
import { Construct } from "constructs";

export class BugfixEventbridgeStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    let inputPathsMap = {
      myName: events.EventField.fromPath("$.detail.name"),
      myUUID: events.EventField.fromPath("$.detail.uuid"),
    };

    const queue = new sqs.Queue(this, "myQueue");

    new events.CfnRule(this, "myCFNrule", {
      name: "myCFNrule",
      eventPattern: {
        source: ["aws.ec2"]
      },
      state: "ENABLED",
      targets: [
        {
          arn: queue.queueArn,
          id: "shared-sqs-cfn",
          inputTransformer: {
            inputTemplate: JSON.stringify(inputPathsMap),
            inputPathsMap: inputPathsMap,
          },
        },
      ],
    });

    const cdkRule = new events.Rule(this, "myCDKrule", {
      ruleName: 'myCDKrule',
      eventPattern: {
        source: ["aws.ec2"]
      }
    });
    cdkRule.addTarget(new targets.SqsQueue(queue, {
      message: events.RuleTargetInput.fromObject(inputPathsMap)
    }));

  }
}


Regression Issue

  • [ ] Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

InputPathsMap is the same for myCFNrule and myCDKrule, using the key/value pairs provided in inputPathsMap

Current Behavior

using the L2 construct (fromObject), keys provided in inputPathsMap are overwritten with system-generated keys. from cdk synth:

  myCFNrule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.ec2
      Name: myCFNrule
      State: ENABLED
      Targets:
        - Arn:
            Fn::GetAtt:
              - myQueue4FDFF71C
              - Arn
          Id: shared-sqs-cfn
          InputTransformer:
            InputPathsMap:
              myName: $.detail.name
              myUUID: $.detail.uuid
            InputTemplate: '{"myName":"$.detail.name","myUUID":"$.detail.uuid"}'
    Metadata:
      aws:cdk:path: BugfixEventbridgeStack/myCFNrule
  myCDKruleB18813AA:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.ec2
      Name: myCDKrule
      State: ENABLED
      Targets:
        - Arn:
            Fn::GetAtt:
              - myQueue4FDFF71C
              - Arn
          Id: Target0
          InputTransformer:
            InputPathsMap:
              detail-name: $.detail.name
              detail-uuid: $.detail.uuid
            InputTemplate: '{"myName":<detail-name>,"myUUID":<detail-uuid>}'
    Metadata:
      aws:cdk:path: BugfixEventbridgeStack/myCDKrule/Resource

Reproduction Steps

run the code provided in issue description

Possible Solution

No response

Additional Information/Context

same issue occurs whether using events.RuleTargetInput.fromObject(inputPathsMap) or events.RuleTargetInput.fromText(JSON.stringify(inputPathsMap))

CDK CLI Version

2.1004.0 (build f0ad96e)

Framework Version

No response

Node.js Version

v23.9.0

OS

Windows

Language

TypeScript

Language Version

[email protected], [email protected]

Other information

No response

kenmacf2 avatar Mar 20 '25 13:03 kenmacf2

Current/Expected Behavior

Image

Technical Analysis

The issue occurs in the implementation of FieldAwareEventInput class, which handles the RuleTargetInput.fromObject() method. When binding the input to a rule target, the class extracts event field path references and creates a mapping from generated keys to the actual JSON paths.

The key generation logic appears to create keys based on the path itself rather than preserving the original object keys from the user's input. This is likely because:

  1. The FieldAwareEventInput class processes the object recursively to find EventField instances
  2. When it encounters an EventField, it generates a key based on the path rather than using the original key from the user's object
  3. This results in the system-generated keys like detail-name instead of user-provided keys like myName

The main problematic code is likely in the implementation of the bind method in the FieldAwareEventInput class.

  1. When extracting fields from the object, the code only collects the EventField instances but doesn't track which object keys they were associated with.
  2. When generating the inputPathsMap, the code creates arbitrary keys like field1, field2, etc., instead of using the original keys from the user's object (like myName, myUUID).

For a complete fix, the FieldAwareEventInput class would need to be modified to:

  1. Track original key-to-field associations when extracting fields
  2. Use those original keys when generating the inputPathsMap instead of creating new keys
  3. Handle cases where the original keys might be nested in a complex object structure

This would make the behavior consistent between the L1 and L2 constructs and provide a more intuitive API for users.

pahud avatar Mar 21 '25 11:03 pahud