Exemplos de transformações

Pode transformar os seus dados CloudEvents escrevendo expressões de transformação com CEL. Para mais informações, consulte o artigo Transforme eventos recebidos.

Seguem-se alguns exemplos de utilização comuns que mostram como escrever expressões CEL para transformar os dados de eventos.

Exemplos de utilização padrão

Seguem-se alguns exemplos de utilização padrão quando transforma dados de eventos.

Normalização de dados

Tem de nivelar uma estrutura de dados aninhada na sua mensagem de evento para permitir um processamento mais fácil por parte de um serviço a jusante.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "orderId": "12345",
    "customerFirstName": "Alex",
    "customerLastName": "Taylor",
    "customerStreet": "1800 Amphibious Blvd.",
    "customerCity": "Mountain View"
  }
}
Solução 1:

Formate os dados de saída manualmente. Isto permite-lhe listar os nomes dos campos e escolher apenas os elementos necessários no resultado. Esta é uma abordagem razoável quando a entrada é previsível e quando o número de campos é baixo. A função setField adiciona ou substitui um campo do evento por uma determinada chave. Por exemplo:

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,
})
Solução 2:

Use uma função na sua expressão. A função setField adiciona ou substitui um campo do evento por uma determinada chave. A função denormalize reduz as estruturas complexas a uma lista de pares de chave e valor. Os nomes dos campos são delimitados com um ponto (.) para segmentar a hierarquia da estrutura. Por exemplo:

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

Isto resulta no seguinte resultado, que difere ligeiramente da carga útil esperada. No entanto, as vantagens incluem uma expressão CEL mais curta que funciona em qualquer entrada e que inclui automaticamente qualquer número de campos recebidos.

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

Ocultação de dados

Tem de ocultar dados confidenciais num payload de eventos antes de o enviar para um ambiente menos seguro.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "userId": "user123",
    "email": "a***@example.com",
    "creditCardNumber": "xxxx-xxxx-xxxx-3456"
  }
}
Solução:

Use uma expressão para ocultar informações confidenciais, como o endereço de email e o número do cartão de crédito. A função setField adiciona ou substitui um campo do evento por uma determinada chave. A função de expressão regular segue a sintaxe RE2.extract Por exemplo:

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"))

Ocultação de dados

Tem de remover campos específicos de uma carga útil de eventos com base em determinadas condições.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  {
  "orderId": "12345",
  "customerType": "gold"
  }
}
Solução:

Use uma expressão que oculte o campo discountCode se o campo customerType for "gold". A função removeFields remove campos específicos de um evento. Por exemplo:

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

Conversão de dados

Precisa de converter dados de um formato ou tipo para outro.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "orderDate": 1704086400,
    "totalAmount": 1500.00
  }
}
Solução:

Use uma expressão que converta orderDate numa indicação de tempo UNIX e o tipo totalAmount de string para double (número de vírgula flutuante). A função setField adiciona ou substitui um campo do evento por uma determinada chave. Pode usar funções de manipulação de strings para converter os resultados de strings. Por exemplo:

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

Encaminhamento condicional

Precisa de encaminhar eventos para diferentes destinos com base nos dados de eventos.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "eventType": "order.created",
    "orderValue": 200,
    "routingKey": "highValue"
  }
}
Solução:

Use uma expressão que adicione um campo routingKey com um "highValue" se o orderValue for superior a 100; caso contrário, "normal". O campo routingKey pode ser usado para determinar o caminho de encaminhamento. A função setField adiciona ou substitui um campo do evento por uma determinada chave. Por exemplo:

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

Processamento de valores predefinidos

Tem de garantir que determinados campos na carga útil do evento têm valores predefinidos se não estiverem presentes.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "itemName": "Product A",
    "quantity": 1
  }
}
Solução:

Use uma expressão que adicione um campo quantity com um valor predefinido de 1 se o campo ainda não existir. A macro has testa se um campo está disponível. A função setField adiciona ou substitui um campo do evento por uma determinada chave. Por exemplo:

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

Manipulação de strings

Tem de extrair ou modificar partes de um campo de string nos dados de eventos.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "customerEmail": "alex@example.com",
    "emailDomain": "example.com"
  }
}
Solução:

Use uma expressão que extraia o nome do domínio ("example.com") do campo customerEmail e o armazene num novo campo emailDomain. A função setField adiciona ou substitui um campo do evento por uma determinada chave. A função de expressão regular segue a sintaxe RE2.extract Por exemplo:

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

Operações de listas e mapas

Precisa de trabalhar com listas ou mapas nos dados de eventos.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "productIds": [
      "product123",
      "product456"
    ],
    "productFound": true
  }
}
Solução:

Use uma expressão que verifique se "product456" existe na lista e armazene o resultado (true ou false) num novo campo productFound.productIds A função setField adiciona ou substitui um campo do evento por uma determinada chave. A macro exists testa se um predicado se aplica a todos os elementos de uma lista e combina os resultados com o operador "ou". Por exemplo:

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

Processamento de erros

Tem de processar corretamente potenciais erros ou dados inesperados no payload do evento.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "quantity": 0,
    "error": "Invalid quantity"
  }
}
Solução:

Use uma expressão que tente converter o campo quantity num inteiro. Se a conversão falhar, defina o campo quantity como 0 e adicione um novo campo error com o valor "Quantidade inválida".

  • A macro has testa se um campo está disponível.
  • A função type devolve o tipo de um valor.
  • A função de expressão regular matches segue a sintaxe RE2.
  • A função setField adiciona ou substitui um campo do evento por uma determinada chave.

Por exemplo:

// 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")

Exemplos de utilização complexos

Seguem-se alguns exemplos de utilização complexos ao transformar dados de eventos.

Transformação de dados

Tem de realizar várias transformações em dados de eventos aninhados.

Cenário:

Tendo em conta os seguintes dados 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
      }
    ]
  }
}

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "orderId": "12345",
    "customer.firstName": "Alex",
    "customer.lastName": "Taylor",
    "customer.email": "a***@example.com",
    "customer.address.city": "Mountain View",
    "customer.address.state": "CA"
  }
}
Solução:

Use uma expressão que extraia a cidade e o estado da morada e que oculte o endereço de email.

  • A função setField adiciona ou substitui um campo do evento por uma determinada chave.
  • A função toMap converte uma lista de CEL de mapas CEL num único mapa CEL.
  • A função de expressão regular extract segue a sintaxe RE2.
  • A função removeFields remove campos específicos de um evento.
  • A função denormalize reduz as estruturas complexas a uma lista de pares de chave e valor. Os nomes dos campos são delimitados com um ponto (.) para segmentar a hierarquia da estrutura.

Por exemplo:

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()
)

Formatação e encaminhamento de dados

Tem de formatar os dados de eventos, adicionar informações sobre os produtos e, em seguida, encaminhar a mensagem de evento.

Cenário:

Tendo em conta os seguintes dados de CloudEvents:

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

Quer escrever uma expressão de IEC que resulte no seguinte resultado:

{
  "data": {
    "productId": "electronics-p123",
    "productName": "EXAMPLE PRODUCT",
    "category": "electronics",
    "routingKey": "electronics"
  }
}
Solução:

Usar uma expressão que formata o nome do produto em maiúsculas, adiciona um prefixo ao ID do produto com base na respetiva categoria e inclui uma chave de encaminhamento para processamento a jusante. A função setField adiciona ou substitui um campo do evento por uma determinada chave. A função upperAscii devolve uma string com todos os carateres ASCII convertidos nos respetivos carateres maiúsculos correspondentes. Por exemplo:

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