EventBridge Input Transformers let you reshape incoming event payloads before they reach your targets, which is surprisingly powerful for decoupling services.
Imagine you have a UserCreated event coming from your user service, and it looks like this:
{
"version": "0",
"id": "a1b2c3d4-e5f6-7890-1234-abcdef123456",
"detail-type": "UserCreated",
"source": "com.mycompany.users",
"account": "123456789012",
"time": "2023-10-27T10:00:00Z",
"region": "us-east-1",
"resources": [],
"detail": {
"userId": "user-123",
"email": "jane.doe@example.com",
"firstName": "Jane",
"lastName": "Doe",
"createdAt": "2023-10-27T09:55:00Z"
}
}
Now, you want to send this to a downstream service that expects a simpler payload, something like:
{
"user_id": "user-123",
"email_address": "jane.doe@example.com",
"full_name": "Jane Doe"
}
EventBridge Input Transformers are the glue that connects these two shapes without requiring modifications to the original event producer or the downstream consumer.
Here’s how it works. When you configure an EventBridge rule, you specify an input transformer for each target. This transformer has two parts: InputPathsMap and InputTemplate.
InputPathsMap is where you define mappings from the incoming event’s JSON structure to named variables. These variables are then available for use in the InputTemplate.
InputTemplate is a string that defines the structure of the output payload. You can embed the variables defined in InputPathsMap directly into this template.
Let’s set up a rule to transform our UserCreated event.
First, we’ll define the InputPathsMap. We want to extract userId, email, firstName, and lastName from the detail object of the incoming event.
{
"userId": "$.detail.userId",
"email": "$.detail.email",
"firstName": "$.detail.firstName",
"lastName": "$.detail.lastName"
}
Here, $.detail.userId is a JSONPath expression that points to the userId field within the detail object of the incoming event.
Next, we’ll define the InputTemplate. We want to create a new JSON object with user_id, email_address, and full_name. We’ll use the variables we defined in the InputPathsMap.
{
"user_id": "<userId>",
"email_address": "<email>",
"full_name": "<firstName> <lastName>"
}
Notice how <userId>, <email>, <firstName>, and <lastName> are placeholders that EventBridge will replace with the actual values extracted from the event. The full_name is constructed by concatenating the firstName and lastName variables with a space in between.
When this rule receives the UserCreated event, EventBridge will:
- Apply the
InputPathsMapto extract values:userIdbecomes"user-123"emailbecomes"jane.doe@example.com"firstNamebecomes"Jane"lastNamebecomes"Doe"
- Substitute these values into the
InputTemplate:"user_id": "user-123""email_address": "jane.doe@example.com""full_name": "Jane Doe"
- Send the resulting JSON payload to the configured target.
This transformation happens before the event is sent to the target. This is crucial because it means your event producers don’t need to know about the specific data formats required by every single downstream consumer. Similarly, your consumers don’t need to be able to parse complex, nested event structures. EventBridge acts as a flexible intermediary.
You can use this for much more than just renaming fields. You can:
- Filter out fields: Simply don’t include a field in the
InputTemplateif you don’t want it. - Concatenate strings: As shown with
full_name. - Reference scalar values: You can map and use any scalar value (strings, numbers, booleans, null) from the event.
- Use literal values: The
InputTemplatecan contain static strings or JSON values that are not derived from the event. For example, you could add asource_system: "user-service"field.
Consider a more complex scenario where you want to enrich an event with a static value and also use a dynamic value from the event. Suppose you’re sending a PaymentProcessed event to a billing system, and you want to include the transaction ID from the event and a fixed currency code of "USD".
Incoming event:
{
"version": "0",
"detail-type": "PaymentProcessed",
"source": "com.mycompany.payments",
"detail": {
"transactionId": "txn_98765",
"amount": 50.75,
"userId": "user-456"
}
}
Input Transformer:
InputPathsMap:
{
"transactionId": "$.detail.transactionId",
"amount": "$.detail.amount"
}
InputTemplate:
{
"payment_id": "<transactionId>",
"transaction_amount": <amount>,
"currency": "USD",
"notes": "Processed via EventBridge"
}
The output payload would be:
{
"payment_id": "txn_98765",
"transaction_amount": 50.75,
"currency": "USD",
"notes": "Processed via EventBridge"
}
Notice how transaction_amount is a number (<amount>) and currency and notes are literal strings.
A common pitfall is misunderstanding how JSONPath expressions work, especially with nested objects or arrays. For instance, if your event had an array of items, $.detail.items[0].name would get the name of the first item. If you wanted all item names, you’d use $.detail.items[*].name which would result in a JSON array of strings in your InputPathsMap variable, which you could then use in your template.
The most surprising thing about Input Transformers is their ability to perform string manipulation by simply concatenating variables and literals within the InputTemplate. You aren’t writing code; you’re defining a declarative string transformation. This allows for sophisticated payload reshaping without any custom lambda functions or external services for simple data wrangling. It leverages the power of JSONPath and template string substitution directly within the EventBridge service.
Once you’ve mastered Input Transformers, you’ll likely want to explore how to use Input Transformers in conjunction with EventBridge Pipes to further simplify data processing pipelines by chaining services together without writing code.