Este contenido no está disponible en el idioma seleccionado.

Chapter 14. Event transformation


EventTransform is a Knative API resource that enables declarative transformations of HTTP requests and responses without requiring custom code. With EventTransform, you can:

  • Modify the event attributes
  • Extract data from the event payloads
  • Reshape events to meet the requirements of different systems

EventTransform is designed as a flexible component in an event-driven architecture. You can place it at various points in the event flow to support seamless integration between diverse producers and consumers.

Note

EventTransform is an addressable resource and can be referenced from Knative sources, triggers, and subscriptions.

14.1. Key features of event transformation

You can use the EventTransform resource to simplify event manipulation, improve flexibility, and enable seamless integration across systems.

Expand
FeatureDescription

Declarative transformations

Define event transformations using standard Kubernetes resources without writing custom code.

JSONata expressions

Use JSONata to extract fields, reshape data, and perform complex transformations.

Addressable resource

Reference EventTransform directly from Knative sources, Triggers, or Subscriptions.

Flexible deployment

Place EventTransform at multiple points in the event flow depending on your architecture needs.

Sink configuration

Route transformed events to specific destinations by defining a sink.

Reply support

Transform and republish events using a built-in reply feature of Broker.

14.2. Common use cases for event transformation

EventTransform enables you to manipulate and reshape events in different ways depending on system requirements. The most common use cases are as follows:

14.2.1. Field extraction

You can extract specific fields from event payloads and expose them as CloudEvent attributes. This makes it easier to filter and route events downstream.

Example of extracting user ID from an event payload

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: extract-user-id
spec:
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,
        "type": "user.extracted",
        "source": "transform.user-extractor",
        "time": time,
        "userid": data.user.id,
        "data": $
      }
Copy to Clipboard Toggle word wrap

14.2.2. Event format conversion

You can convert the structure of an event into a different format so that it remains compatible with diverse consumer systems.

Example of converting an order event to a customer-centric format

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: format-converter
spec:
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: destination-service
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,
        "type": "order.converted",
        "source": "transform.format-converter",
        "time": time,
        "data": {
          "orderId": data.id,
          "customer": {
            "name": data.user.fullName,
            "email": data.user.email
          },
          "items": data.items
        }
      }
Copy to Clipboard Toggle word wrap

14.2.3. Event enrichment

You can add fixed or dynamic metadata such as environment or region to events without requiring any changes in the original producer.

Example of adding environment and region metadata to the event

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: event-enricher
spec:
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,                     /* Add the "id", "type", "source", and "time" attributes based on the input JSON object fields */
        "type": type,
        "source": source,
        "time": time,
        "environment": "production",  /* Add fixed environment and region attributes to the event metadata */
        "region": "us-west-1",
        "data": $                     /* Add the event transform input JSON body as CloudEvent "data" field */
      }
Copy to Clipboard Toggle word wrap

14.2.4. Event response reply transformation

You can transform not only the request sent to a sink but also the response received from the sink, enabling end-to-end event shaping.

Example of transforming both request and reply messages

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: request-reply-transform
spec:
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: processor-service
  jsonata:
    expression: |
      # Request transformation
      {
        "specversion": "1.0",
        "id": id,
        "type": "request.transformed",
        "source": source,
        "time": time,
        "data": data
      }
  reply:
    jsonata:
      expression: |
        # Reply transformation
        {
          "specversion": "1.0",
          "id": id,
          "type": "reply.transformed",
          "source": "transform.reply-processor",
          "time": time,
          "data": data
        }
Copy to Clipboard Toggle word wrap

14.3. Deployment patterns for event transformation

You can use EventTransform at different points in your event flow depending on your architecture needs. The following patterns are supported:

14.3.1. Source to Broker event transformation

You can route events from a Source to an EventTransform resource, apply transformation logic, and then forward them to a Broker so that only normalised or enriched events are routed for consumption.

You can configure an ApiServerSource resource to send events to an EventTransform resource, which then transforms and routes them to the default Broker, as shown in the following example:

apiVersion: sources.knative.dev/v1
kind: ApiServerSource
metadata:
  name: k8s-events
spec:
  serviceAccountName: event-watcher
  resources:
    - apiVersion: v1
      kind: Event
  sink:
    ref:
      apiVersion: eventing.knative.dev/v1alpha1
      kind: EventTransform
      name: event-transformer
---
apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: event-transformer
spec:
  sink:
    ref:
      apiVersion: eventing.knative.dev/v1
      kind: Broker
      name: default
  jsonata:
    expression: |
      # transformation expression
Copy to Clipboard Toggle word wrap

14.3.2. Trigger to Service event transformation

You can route events through Broker Trigger EventTransform Service or Sink. The Broker receives all events, the Trigger filters them by attributes, the EventTransform resource reshapes or enriches the filtered events, and the Service or Sink processes the results.

You can tailor events for specific consumers without changing the original producer or affecting other subscribers. Because transformations apply only after filtering, only relevant events are reshaped, which improves efficiency and reduces unnecessary processing.

You can filter events of type original.event.type, route them to an EventTransform, and deliver the transformed events to a Service with this configuration.

apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
  name: transform-trigger
spec:
  broker: default
  filter:
    attributes:
      type: original.event.type
  subscriber:
    ref:
      apiVersion: eventing.knative.dev/v1alpha1
      kind: EventTransform
      name: event-transformer
---
apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: event-transformer
spec:
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: destination-service
  jsonata:
    expression: |
      # transformation expression
Copy to Clipboard Toggle word wrap

14.3.3. Broker reply event transformation

You can configure EventTransform without a sink to republish transformed events back to the Broker, where they can be routed to additional Triggers or consumers.

Note

When using the Broker reply feature, ensure the transformed events do not match the same Trigger that invoked the EventTransform. Otherwise, you risk creating an infinite event loop.

You can filter events of type original.event.type with a Trigger, transform them with EventTransform, and republish them to the Broker as transformed.event.type type. Updating the type or another attribute routes the event to different Triggers without reprocessing by the same Trigger.

apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
  name: transform-trigger
spec:
  broker: default
  filter:
    attributes:
      type: original.event.type
  subscriber:
    ref:
      apiVersion: eventing.knative.dev/v1alpha1
      kind: EventTransform
      name: event-transformer
---
apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: event-transformer
spec:
  # No sink specified - reply to Broker
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,
        "time": time,
        "type": "transformed.event.type",
        "source": "transform.event-transformer",
        "data": $
      }
Copy to Clipboard Toggle word wrap

14.4. Event transformations for JSON with JSONata

JSONata is a lightweight query and transformation language for JSON data. Within Knative EventTransform, JSONata expressions provide an important way to reshape events. You can use them to extract values from event data, promote specific fields to CloudEvent attributes, restructure entire payloads, add computed values, and even apply conditional logic to control how events are transformed.

You can specify a JSONata expression in the spec.jsonata.expression field of the EventTransform resource. The expression maps the incoming CloudEvent into a new CloudEvent as shown in the following example:

Example of simple event transformation using JSONata

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: simple-transform
spec:
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,
        "time": time,
        "type": "transformed.type",
        "source": "transform.simple",
        "data": data
      }
Copy to Clipboard Toggle word wrap

14.4.1. CloudEvent structure in JSONata

When you use JSONata in an EventTransform, the input to the expression is the full CloudEvent object, which includes all standard attributes and the event payload.

The output of your JSONata expression must produce a valid CloudEvent. At a minimum, the following fields are required to ensure compliance with the CloudEvents specification:

Expand
FieldRequirementDescription

specversion

Must be 1.0

Identifies the CloudEvents specification version.

id

Unique string

Serves as the unique identifier for the event.

type

Required

Indicates the event type, such as com.example.object.created.

source

Required

Identifies the context in which the event occurred.

data

Required

Contains the event payload being delivered.

By explicitly constructing these fields in your JSONata expression, you ensure that the transformed event is valid while still applying reshaping, enrichment, or conditional logic as needed.

14.5. Common transformation patterns

To effectively shape your event data, you can leverage common JSONata transformation patterns for preserving, extracting, restructuring, or conditionally modifying events.

14.5.1. Preserving the original event structure

You can add or adjust attributes while keeping the rest of the event unchanged, so that downstream consumers receive the original data with minimal modifications.

Example of adding a static attribute while preserving the original event structure

{
  "specversion": "1.0",
  "id": id,
  "type": type,
  "source": source,
  "time": time,
  "data": data,
  "newattribute": "static value"
}
Copy to Clipboard Toggle word wrap

14.5.2. Extracting fields as attributes

You can promote values from the payload to top-level CloudEvent attributes to make filtering and routing easier.

Example of extracting user ID and region from the payload and expose them as attributes

{
  "specversion": "1.0",
  "id": id,
  "type": "user.event",
  "source": source,
  "time": time,
  "userid": data.user.id,
  "region": data.region,
  "data": $
}
Copy to Clipboard Toggle word wrap

In JSONata, the $ symbol represents the entire input object. Using data: $ preserves the original event payload while promoting selected fields.

14.5.3. Restructuring an event data

Use JSONata to transform events into the schema required by another system by restructuring payloads, renaming fields, nesting objects, and performing calculations.

Example of restructuring an order event and calculate the total value of items

{
  "specversion": "1.0",
  "id": order.id,
  "type": "order.transformed",
  "source": "transform.order-processor",
  "time": order.time,
  "orderid": order.id,
  "data": {
    "customer": {
      "id": order.user.id,
      "name": order.user.name
    },
    "items": order.items.{ "sku": sku, "quantity": qty, "price": price },
    "total": $sum(order.items.(price * qty))
  }
}
Copy to Clipboard Toggle word wrap

Given the transformation above, and this JSON object as input:

{
  "order": {
    "time": "2024-04-05T17:31:05Z",
    "id": "8a76992e-cbe2-4dbe-96c0-7a951077089d",
    "user": {
      "id": "bd9779ef-cba5-4ad0-b89b-e23913f0a7a7",
      "name": "John Doe"
    },
    "items": [
      {"sku": "KNATIVE-1", "price": 99.99, "qty": 1},
      {"sku": "KNATIVE-2", "price": 129.99, "qty": 2}
    ]
  }
}
}
Copy to Clipboard Toggle word wrap

The transformation produces the following output:

{
  "specversion": "1.0",
  "id": "8a76992e-cbe2-4dbe-96c0-7a951077089d",
  "type": "order.transformed",
  "source": "transform.order-processor",
  "time": "2024-04-05T17:31:05Z",
  "orderid": "8a76992e-cbe2-4dbe-96c0-7a951077089d",
  "data": {
    "customer": {
      "id": "bd9779ef-cba5-4ad0-b89b-e23913f0a7a7",
      "name": "John Doe"
    },
    "items": [
      {
        "sku": "KNATIVE-1",
        "quantity": 1,
        "price": 99.99
      },
      {
        "sku": "KNATIVE-2",
        "quantity": 2,
        "price": 129.99
      }
    ],
    "total": 359.97
  }
}
Copy to Clipboard Toggle word wrap

Use this pattern to integrate with APIs that require specific structures or calculated fields.

14.5.4. Conditional transformations

With JSONata, you can embed conditional logic directly into your transformation, enabling dynamic event shaping based on attributes or payload values.

Example of applying different types and priorities based on conditions

{
  "specversion": "1.0",
  "id": id,
  "type": type = "order.created" ? "new.order" : "updated.order",
  "source": source,
  "time": time,
  "priority": data.total > 1000 ? "high" : "normal",
  "data": $
}
Copy to Clipboard Toggle word wrap

In the given example:

  • If the event type is order.created, the new type becomes new.order; otherwise, it is set to updated.order.
  • If the total field in the payload is greater than 1000, a priority attribute is added with the value high; otherwise, it is set to normal.

14.6. Advanced JSONata features

You can use JSONata to transform events more effectively by applying advanced features such as array processing and built-in functions.

14.6.1. Array processing

JSONata makes it easy to work with arrays in event payloads. You can count items, filter them based on conditions, and calculate aggregate values.

Example of processing items in an order and compute totals

{
  "specversion": "1.0",
  "id": id,
  "type": "order.processed",
  "source": source,
  "time": $now(),
  "itemcount": $count(order.items),
  "multiorder": $count(order.items) > 1,
  "data": {
    "order": order.id,
    "items": order.items[quantity > 1].{
      "product": name,
      "quantity": quantity,
      "lineTotal": price * quantity
    },
    "totalvalue": $sum(order.items.(price * quantity))
  }
}
Copy to Clipboard Toggle word wrap

Given this as an input:

{
  "id": "12345",
  "source": "https://example.com/orders",
  "order": {
    "id": "order-67890",
    "items": [
      { "name": "Laptop", "price": 1000, "quantity": 1 },
      { "name": "Mouse", "price": 50, "quantity": 2 },
      { "name": "Keyboard", "price": 80, "quantity": 3 }
    ]
  }
}
Copy to Clipboard Toggle word wrap

The transformation produces the following output:

{
  "specversion": "1.0",
  "id": "12345",
  "type": "order.processed",
  "source": "https://example.com/orders",
  "time": "2025-03-03T09:13:23.753Z",
  "itemcount": 3,
  "multiorder": true,
  "data": {
    "order": "order-67890",
    "items": [
      { "product": "Mouse", "quantity": 2, "lineTotal": 100 },
      { "product": "Keyboard", "quantity": 3, "lineTotal": 240 }
    ],
    "totalvalue": 1340
  }
}
Copy to Clipboard Toggle word wrap

In this example:

  • $count(order.items) counts how many items are in the array.
  • The filter [quantity > 1] selects only items with quantity greater than one.
  • $sum(order.items.(price * quantity)) calculates the total value.

14.6.2. Using built-in functions

JSONata includes a wide range of built-in functions that can manipulate strings, numbers, dates, and arrays. These functions can enrich events with new fields derived from existing data.

Example of adding metadata using built-in functions

{
  "specversion": "1.0",
  "id": id,
  "type": "user.event",
  "source": source,
  "time": time,
  "timestamp": $now(),
  "username": $lowercase(data.user.name),
  "initials": $join($map($split(data.user.name, " "), function($v) { $substring($v, 0, 1) }), ""),
  "data": $
}
Copy to Clipboard Toggle word wrap

In this example:

  • $now() adds the current timestamp.
  • $lowercase() converts the user name to lowercase.
  • $split() breaks the name into parts, $map() extracts the first letter of each, and $join() combines them into initials.

14.7. Transforming replies

You can configure an EventTransform resource to modify both incoming requests and the responses returned from a sink in request–reply scenarios.

Note

You must use the same type of transformation for both the request and the reply. For example, JSONata with JSONata.

The following example shows how to transform both request and reply events:

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: request-reply-transform
spec:
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: processor-service
  jsonata:
    expression: |
      # Request transformation
      {
        "specversion": "1.0",
        "id": id,
        "type": "request.transformed",
        "source": source,
        "time": time,
        "data": data
      }
  reply:
    jsonata:
      expression: |
        # Reply transformation
        {
          "specversion": "1.0",
          "id": id,
          "type": "reply.transformed",
          "source": "transform.reply-processor",
          "time": time,
          "data": data
        }
Copy to Clipboard Toggle word wrap

14.8. Event transformation examples

You can use these examples to apply JSONata in EventTransform resources to reshape and enrich events for common business scenarios.

14.8.1. User registration event transformer

You can use the following example to process user registration events by normalising email addresses, deriving a display name if missing, setting a registration timestamp, and applying default values for region and subscription tier.

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: user-registration-transformer
spec:
  sink:
    ref:
      apiVersion: eventing.knative.dev/v1
      kind: Broker
      name: default
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,
        "type": "user.registered.processed",
        "source": "transform.user-processor",
        "time": time,
        "userid": data.user.id,
        "region": data.region ? data.region : "unknown",
        "tier": data.subscription.tier ? data.subscription.tier : "free",
        "data": {
          "userId": data.user.id,
          "email": $lowercase(data.user.email),
          "displayName": data.user.name ? data.user.name : $substring(data.user.email, 0, $indexOf(data.user.email, "@")),
          "registrationDate": $now(),
          "subscription": data.subscription ? data.subscription : { "tier": "free" }
        }
      }
Copy to Clipboard Toggle word wrap

14.8.2. Order processing event transformer

The following example processes order events. It calculates totals, tax, and grand total, determines the order priority, and enriches the event with processing timestamps:

apiVersion: eventing.knative.dev/v1alpha1
kind: EventTransform
metadata:
  name: order-processor
spec:
  jsonata:
    expression: |
      {
        "specversion": "1.0",
        "id": id,
        "type": "order.processed",
        "source": "transform.order-processor",
        "time": time,
        "orderid": data.id,
        "customerid": data.customer.id,
        "region": data.region,
        "priority": $sum(data.items.(price * quantity)) > 1000 ? "high" : "standard",
        "data": {
          "orderId": data.id,
          "customer": data.customer,
          "items": data.items.{
            "productId": productId,
            "name": name,
            "quantity": quantity,
            "unitPrice": price,
            "totalPrice": price * quantity
          },
          "total": $sum(data.items.(price * quantity)),
          "tax": $sum(data.items.(price * quantity)) * 0.1,
          "grandTotal": $sum(data.items.(price * quantity)) * 1.1,
          "created": data.created,
          "processed": $now()
        }
      }
Copy to Clipboard Toggle word wrap
Volver arriba
Red Hat logoGithubredditYoutubeTwitter

Aprender

Pruebe, compre y venda

Comunidades

Acerca de la documentación de Red Hat

Ayudamos a los usuarios de Red Hat a innovar y alcanzar sus objetivos con nuestros productos y servicios con contenido en el que pueden confiar. Explore nuestras recientes actualizaciones.

Hacer que el código abierto sea más inclusivo

Red Hat se compromete a reemplazar el lenguaje problemático en nuestro código, documentación y propiedades web. Para más detalles, consulte el Blog de Red Hat.

Acerca de Red Hat

Ofrecemos soluciones reforzadas que facilitan a las empresas trabajar en plataformas y entornos, desde el centro de datos central hasta el perímetro de la red.

Theme

© 2025 Red Hat