Ejemplos de transformación

Puedes transformar tus datos de CloudEvents escribiendo expresiones de transformación con CEL. Para obtener más información, consulta Cómo transformar los eventos recibidos.

Los siguientes son algunos casos de uso y ejemplos comunes que te muestran cómo escribir expresiones de CEL para transformar tus datos de eventos.

Casos de uso estándar

Los siguientes son algunos casos de uso estándar cuando se transforman los datos de eventos.

Normalización de datos

Debes aplanar una estructura de datos anidada en el mensaje del evento para permitir que un servicio downstream la procese de forma más fácil.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "orderId": "12345",
    "customer": {
      "firstName": "Alex",
      "lastName": "Taylor",
      "address": {
        "street": "1800 Amphibious Blvd.",
        "city": "Mountain View"
      }
    }
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "orderId": "12345",
    "customerFirstName": "Alex",
    "customerLastName": "Taylor",
    "customerStreet": "1800 Amphibious Blvd.",
    "customerCity": "Mountain View"
  }
}
Solución 1:

Dales formato a los datos de salida de forma manual. Esto te permite enumerar los nombres de los campos y elegir solo los elementos necesarios en el resultado. Este es un enfoque razonable cuando la entrada es predecible y la cantidad de campos es baja. La función setField agrega o reemplaza un campo del evento con una clave determinada. Por ejemplo:

message.setField("data",
{
  "orderId": message.data.orderId,
  "customerFirstName": message.data.customer.firstName,
  "customerLastName": message.data.customer.lastName,
  "customerStreet": message.data.customer.address.street,
  "customerCity": message.data.customer.address.city,
})
Solución 2:

Usa una función en tu expresión. La función setField agrega o reemplaza un campo del evento con una clave determinada. La función denormalize aplana las estructuras profundas en una lista de pares clave-valor. Los nombres de campo se delimitan con un punto (.) para segmentar la jerarquía de la estructura. Por ejemplo:

message.setField("data", message.data.denormalize())

Esto genera el siguiente resultado, que difiere ligeramente de la carga útil esperada. Sin embargo, las ventajas incluyen una expresión CEL más corta que opera en cualquier entrada y que incluye automáticamente cualquier cantidad de campos entrantes.

{
  "data": {
    "orderId": "12345",
    "customer.firstName": "Alex",
    "customer.lastName": "Taylor",
    "customer.address.street": "1800 Amphibious Blvd.",
    "customer.address.city": "Mountain View"
  }
}

Enmascarar datos

Debes enmascarar los datos sensibles en una carga útil de evento antes de que se envíen a un entorno menos seguro.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "userId": "user123",
    "email": "alex@example.com",
    "creditCardNumber": "1234-5678-9012-3456"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "userId": "user123",
    "email": "a***@example.com",
    "creditCardNumber": "xxxx-xxxx-xxxx-3456"
  }
}
Solución:

Usa una expresión para enmascarar cualquier información sensible, como la dirección de correo electrónico y el número de tarjeta de crédito. La función setField agrega o reemplaza un campo del evento con una clave determinada. La función de expresión regular extract sigue la sintaxis RE2. Por ejemplo:

message
      .setField("data.email",
          re.extract(message.data.email,
                    "(^.).*@(.*)",
                    "\\1***@\\2"))

      .setField("data.creditCardNumber",
          re.extract(message.data.creditCardNumber,
                    "(\\d{4})\\D*$",
                    "xxxx-xxxx-xxxx-\\1"))

Ocultación de datos

Debes quitar campos específicos de una carga útil de evento según ciertas condiciones.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "orderId": "12345",
    "customerType": "gold",
    "discountCode": "VIP"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  {
  "orderId": "12345",
  "customerType": "gold"
  }
}
Solución:

Usa una expresión que oculte el campo discountCode si customerType es “oro”. La función removeFields quita campos específicos de un evento. Por ejemplo:

message.data.customerType == "gold" ?
      message.removeFields(["data.discountCode"]) :
      message

Conversión de datos

Debes convertir los datos de un formato o tipo a otro.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "orderDate": "2024-10-31T12:00:00Z",
    "totalAmount": "1500"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "orderDate": 1704086400,
    "totalAmount": 1500.00
  }
}
Solución:

Usa una expresión que convierta orderDate en una marca de tiempo de UNIX y el tipo totalAmount de string a double (número de punto flotante). La función setField agrega o reemplaza un campo del evento con una clave determinada. Puedes usar funciones de manipulación de cadenas para convertir los resultados de las cadenas. Por ejemplo:

message
      .setField("data.orderDate", int(timestamp(message.data.orderDate)))
      .setField("data.totalAmount", double(message.data.totalAmount))

Enrutamiento condicional

Debes enrutar los eventos a diferentes destinos según los datos del evento.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "eventType": "order.created",
    "orderValue": 200
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "eventType": "order.created",
    "orderValue": 200,
    "routingKey": "highValue"
  }
}
Solución:

Usa una expresión que agregue un campo routingKey con un "valor alto" si orderValue es mayor que 100; de lo contrario, "normal". El campo routingKey se puede usar para determinar la ruta de enrutamiento. La función setField agrega o reemplaza un campo del evento con una clave determinada. Por ejemplo:

message.data.orderValue > 100 ?
      message.setField("data.routingKey", "highValue") :
      message.setField("data.routingKey", "normal")

Control de valores predeterminados

Debes asegurarte de que ciertos campos de la carga útil del evento tengan valores predeterminados si no están presentes.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "itemName": "Product A"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "itemName": "Product A",
    "quantity": 1
  }
}
Solución:

Usa una expresión que agregue un campo quantity con un valor predeterminado de 1 si el campo aún no existe. La macro has comprueba si un campo está disponible. La función setField agrega o reemplaza un campo del evento con una clave determinada. Por ejemplo:

has(message.data.quantity)  ?
    message :
    message.setField("data.quantity", 1)

Manipulación de cadenas

Debes extraer o modificar partes de un campo de cadena en los datos del evento.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "customerEmail": "alex@example.com"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "customerEmail": "alex@example.com",
    "emailDomain": "example.com"
  }
}
Solución:

Usa una expresión que extraiga el nombre de dominio ("example.com") del campo customerEmail y lo almacene en un campo emailDomain nuevo. La función setField agrega o reemplaza un campo del evento con una clave determinada. La función de expresión regular extract sigue la sintaxis RE2. Por ejemplo:

message
  .setField("data.emailDomain",
re.extract(message.data.customerEmail, "(^.*@)(.*)", "\\2"))

Operaciones de lista y asignación

Debes trabajar con listas o mapas en los datos del evento.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "productIds": [
      "product123",
      "product456"
    ]
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "productIds": [
      "product123",
      "product456"
    ],
    "productFound": true
  }
}
Solución:

Usa una expresión que verifique si "product456" existe en la lista productIds y almacene el resultado (true o false) en un nuevo campo productFound. La función setField agrega o reemplaza un campo del evento con una clave determinada. La macro exists prueba si un predicado se cumple para todos los elementos de una lista y combina los resultados con el operador "o". Por ejemplo:

message.setField("data.productFound",
        message.data.productIds.exists(id, id == "product123"))

Manejo de errores

Debes controlar de forma fluida los posibles errores o datos inesperados en la carga útil del evento.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "quantity": "abc"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "quantity": 0,
    "error": "Invalid quantity"
  }
}
Solución:

Usa una expresión que intente convertir el campo quantity en un número entero. Si la conversión falla, establece el campo quantity en 0 y agrega un campo error nuevo con el valor "Cantidad no válida".

  • La macro has comprueba si un campo está disponible.
  • La función type muestra el tipo de un valor.
  • La función de expresión regular matches sigue la sintaxis RE2.
  • La función setField agrega o reemplaza un campo del evento con una clave determinada.

Por ejemplo:

// Check if data.quantity exists
has(message.data.quantity) &&
// Check if data.quantity is a string
type(message.data.quantity) == string &&
// Check if string consists of digits
message.data.quantity.matches(r'^-?[0-9]+$') ?
  // If data.quantity is valid, use message
  message :
  // If data.quantity is invalid, set to 0 and generate error
  message
    .setField("data.quantity", 0)
    .setField("data.error", "Invalid quantity")

Casos de uso complejos

Los siguientes son algunos casos de uso complejos cuando se transforman los datos de eventos.

Transformación de datos

Debes realizar varias transformaciones en los datos de eventos anidados.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "orderId": "12345",
    "customer": {
      "firstName": "Alex",
      "lastName": "Taylor",
      "email": "alex@example.com",
      "address": {
        "street": "1800 Amphibious Blvd.",
        "city": "Mountain View",
        "state": "CA"
      }
    },
    "items": [
      {
        "itemId": "item1",
        "price": 10.00,
        "quantity": 2
      },
      {
        "itemId": "item2",
        "price": 5.00,
        "quantity": 1
      }
    ]
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "orderId": "12345",
    "customer.firstName": "Alex",
    "customer.lastName": "Taylor",
    "customer.email": "a***@example.com",
    "customer.address.city": "Mountain View",
    "customer.address.state": "CA"
  }
}
Solución:

Usa una expresión que extraiga la ciudad y el estado de la dirección y que oculte la dirección de correo electrónico.

  • La función setField agrega o reemplaza un campo del evento con una clave determinada.
  • La función toMap convierte una lista de mapas CEL en un solo mapa CEL.
  • La función de expresión regular extract sigue la sintaxis RE2.
  • La función removeFields quita campos específicos de un evento.
  • La función denormalize aplana las estructuras profundas en una lista de pares clave-valor. Los nombres de campo se delimitan con un punto (.) para segmentar la jerarquía de la estructura.

Por ejemplo:

message
.setField("data",
  message.data.setField("customer.address",
    message.data.customer.address.map(key, key == "city" || key == "state",
          { key: message.data.customer.address[key] }).toMap())
  .setField("customer.email",
        re.extract(message.data.customer.email, "(^..?).*@(.*)", "\\1***@\\2"))
  .removeFields(["items"])
  .denormalize()
)

Enrutamiento y formato de datos

Debes dar formato a los datos del evento, agregar información del producto y, luego, enrutar el mensaje del evento.

Situación:

Con los siguientes datos de CloudEvents:

{
  "data": {
    "productId": "p123",
    "productName": "Example Product",
    "category": "electronics"
  }
}

Supongamos que quieres escribir una expresión CEL que genere el siguiente resultado:

{
  "data": {
    "productId": "electronics-p123",
    "productName": "EXAMPLE PRODUCT",
    "category": "electronics",
    "routingKey": "electronics"
  }
}
Solución:

Usa una expresión que aplique formato al nombre del producto en mayúsculas, agregue un prefijo al ID del producto según su categoría y, además, incluya una clave de enrutamiento para el procesamiento descendente. La función setField agrega o reemplaza un campo del evento con una clave determinada. La función upperAscii muestra una cadena con todos los caracteres ASCII convertidos en sus caracteres en mayúsculas correspondientes. Por ejemplo:

message
.setField("data.productId",
message.data.category + "-" + message.data.productId)
.setField("data.productName", message.data.productName.upperAscii())
.setField("data.routingKey", message.data.category)