As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Transformar dados com JSONata no Step Functions
Com o JSONata, você obtém uma poderosa linguagem de consulta e expressão de código aberto para selecionar e transformar dados em seus fluxos de trabalho. Para uma breve introdução e uma referência completa do JSonata, consulte JSONata.org a documentação.
Versão JSonata suportada
Step Functions suporta JSonata versão 2.0.6.
O seguinte vídeo descreve variáveis e JSONata no Step Functions com um exemplo do DynamoDB:
Você deve optar por usar a linguagem de consulta e transformação JSONata em fluxos de trabalho existentes. Ao criar um fluxo de trabalho no console, recomendamos escolher JSONata para a máquina de estado de nível superior QueryLanguage. Em fluxos de trabalho novos ou existentes que usam JSONPath, o console oferece uma opção para converter estados individuais em JSONata.
Após selecionar JSONata, os campos de fluxo de trabalho serão reduzidos de cinco campos JSONPath (InputPath, Parameters, ResultSelector, ResultPath e OutputPath) para apenas dois campos: Arguments e Output. Além disso, você não usará .$ em nomes de chaves de objetos JSON.
Se você não conhece o Step Functions, só precisa saber que as expressões JSONata usam a seguinte sintaxe:
Sintaxe JSONata: "{% <JSONata expression> %}"
Os seguintes exemplos de código mostram uma conversão de JSONPath para JSONata:
# Original sample using JSONPath
{
"QueryLanguage": "JSONPath", // Set explicitly; could be set and inherited from top-level
"Type": "Task",
...
"Parameters": {
"static": "Hello",
"title.$": "$.title",
"name.$": "$customerName", // With $customerName declared as a variable
"not-evaluated": "$customerName"
}
}
# Sample after conversion to JSONata
{
"QueryLanguage": "JSONata", // Set explicitly; could be set and inherited from top-level
"Type": "Task",
...
"Arguments": { // JSONata states do not have Parameters
"static": "Hello",
"title": "{% $states.input.title %}",
"name": "{% $customerName %}", // With $customerName declared as a variable
"not-evaluated": "$customerName"
}
}
Com a entrada { "title" : "Doctor" } e a variável customerName atribuídas para "María", ambas as máquinas de estado produzirão o seguinte resultado JSON:
{
"static": "Hello",
"title": "Doctor",
"name": "María",
"not-evaluated": "$customerName"
}
No seguinte diagrama, você pode ver uma representação gráfica mostrando como a conversão de JSONPath (à esquerda) em JSONata (à direita) reduzirá a complexidade das etapas em suas máquinas de estado:
Opcionalmente, você pode selecionar e transformar dados da entrada de estado em argumentos para enviar para sua ação integrada. Com o JSONata, você opcionalmente pode selecionar e transformar os resultados da ação para atribuir a variáveis e ao estado Saída.
Observação: as etapas Atribuir e Saída ocorrem em paralelo. Se você optar por transformar dados durante a atribuição de variáveis, esses dados transformados não estarão disponíveis na etapa Saída. Você deve reaplicar a transformação JSONata na etapa Saída.
QueryLanguage campo
Nas definições de ASL do seu fluxo de trabalho, há um campo QueryLanguage no nível superior de uma definição de máquina de estado e em estados individuais. Ao configurar QueryLanguage dentro de estados individuais, você pode adotar o JSONata de forma incremental em uma máquina de estado existente em vez de atualizar a máquina de estado de uma só vez.
O campo QueryLanguage pode ser definido como "JSONPath" ou "JSONata". Se o campo QueryLanguage de nível superior for omitido, o padrão será "JSONPath". Se um estado contiver um campo QueryLanguage em nível de estado, o Step Functions usará a linguagem de consulta especificada para esse estado. Se o estado não contiver um campo QueryLanguage, ele usará a linguagem de consulta especificada no campo QueryLanguage de nível superior.
Escrever expressões JSONata em strings JSON
Quando uma string no valor de um campo ASL, um campo de objeto JSON ou um elemento de matriz JSON é cercado por caracteres {% %}, essa string será avaliada como JSONata. Observe que a string deve começar com {% sem espaços iniciais e terminar com %} sem espaços finais. Abrir ou fechar a expressão de forma inadequada resultará em um erro de validação.
Alguns exemplos:
-
"TimeoutSeconds" : "{% $timeout %}" -
"Arguments" : {"field1" : "{% $name %}"}em um estadoTask -
"Items": [1, "{% $two %}", 3]em um estadoMap
Nem todos os campos ASL aceitam JSONata. Por exemplo, o campo Type de cada estado deve ser definido como uma string constante. Da mesma forma, o campo Resource do estado Task deve ser uma string constante. O Items campo Map state aceitará uma matriz JSON, um objeto JSON ou uma expressão JSONata que deve ser avaliada como uma matriz ou objeto.
Variável reservada: $states
Step Functions define uma única variável reservada chamada $states. Nos estados JSONata, as seguintes estruturas são atribuídas a $states para uso em expressões JSONata:
# Reserved $states variable in JSONata states
$states = {
"input": // Original input to the state
"result": // API or sub-workflow's result (if successful)
"errorOutput": // Error Output (only available in a Catch)
"context": // Context object
}
Na entrada de estado, Step Functions atribui a entrada de estado a. $states.input O valor de $states.input pode ser usado em todos os campos que aceitam expressões JSONata. $states.input sempre se refere à entrada do estado original.
Para os estados Task, Parallel e Map:
-
$states.resultse refere ao resultado bruto da API ou do subfluxo de trabalho, se for bem-sucedido. -
$states.errorOutputrefere-se à saída de erro se a API ou o subfluxo de trabalho falharem.$states.errorOutputpode ser usado nos camposAssignouOutputdeCatch.
A tentativa de acessar $states.result ou $states.errorOutput em campos e estados onde eles não estão acessíveis será detectada na criação, atualização ou validação da máquina de estado.
O objeto $states.context fornece aos fluxos de trabalho informações sobre sua execução específica, como StartTime, o token de tarefa e a entrada inicial do fluxo de trabalho. Para saber mais, consulteAcessar dados de execução do objeto de contexto no Step Functions.
Gerenciar erros de expressão
Em runtime, a avaliação da expressão JSONata pode falhar por vários motivos, como:
-
Erro de tipo: uma expressão, como
{% $x + $y %}, falhará se$xou$ynão for um número. -
Incompatibilidade de tipo: uma expressão pode ser avaliada como um tipo que o campo não aceitará. Por exemplo, o campo
TimeoutSecondsexige uma entrada numérica, então a expressão{% $timeout %}falhará se$timeoutretornar uma string. -
Valor fora do intervalo: uma expressão que produz um valor fora do intervalo aceitável para um campo falhará. Por exemplo, uma expressão como
{% $evaluatesToNegativeNumber %}falhará no campoTimeoutSeconds. -
Falha ao retornar um resultado: o JSON não pode representar uma expressão de valor indefinido, portanto, a expressão
{% $data.thisFieldDoesNotExist %}resultaria em erro. -
Limite de memória excedido - Uma expressão JSonata que consome muita memória durante a avaliação falhará com um erro.
Expression evaluation memory limit exceededIsso pode ocorrer com expressões que processam ou transformam grandes quantidades de dados. Para contornar essa limitação, considere mover a transformação de dados para uma função Lambda. -
Tempo limite da expressão - Uma expressão JSonata que leva mais de 1 segundo para ser avaliada falhará com um erro.
Expression evaluation timeoutIsso pode ocorrer com expressões que contêm loops infinitos ou operações muito caras. -
Stack overflow - Uma expressão JSonata que excede a profundidade máxima de recursão falhará com a.
Stack overflow errorSe a recursão não terminar, certifique-se de que a função tenha um caso base ou condição de encerramento corretos. Se a recursão terminar, mas a pilha de chamadas ficar muito profunda, considere reescrever a função como recursiva de cauda para reduzir a profundidade da pilha.
Em cada caso, o intérprete lançará o erro: States.QueryEvaluationError. Seus estados de Tarefa, Mapa e Paralelo podem fornecer um campo Catch para capturar o erro e um campo Retry para tentar novamente o erro.
Converter JSONPath para JSONata
As seções a seguir comparam e explicam as diferenças entre o código escrito com JSONPath e JSONata.
Sem campos de caminho
A ASL exige que os desenvolvedores usem versões de Path de campos, como em TimeoutSecondsPath, para selecionar um valor dos dados de estado ao usar o JSONPath. Ao usar JSONata, os campos Path não são mais usados porque a ASL interpreta expressões JSONata delimitadas por {% %} automaticamente para você em campos que não sejam Path, como TimeoutSeconds.
-
Exemplo de JSONPath legado:
"TimeoutSecondsPath": "$timeout" -
JSONata:
"TimeoutSeconds": "{% $timeout %}"
Da mesma forma, o Map estado ItemsPath foi substituído pelo Items campo que aceita uma matriz JSON, um objeto JSON ou uma expressão JSONata que deve ser avaliada como uma matriz ou objeto.
Objetos JSON
A ASL usa o termo modelo de carga útil para descrever um objeto JSON que pode conter expressões JSONPath para valores de campo Parameters e ResultSelector. A ASL não usará o termo modelo de carga útil para JSONata porque a avaliação de JSONata acontece para todas as strings, independentemente se elas ocorrerem sozinhas em um objeto JSON ou de uma matriz JSON.
Sem .$
A ASL exige que você acrescente “.$” aos nomes dos campos nos modelos de carga útil para usar JSONPath e funções intrínsecas. Ao especificar "QueryLanguage":"JSONata", você não usa mais a convenção “.$” para nomes de campos de objetos JSON. Em vez disso, você envolve expressões JSONata em caracteres {% %}. A mesma convenção é usada em todos os campos com valor de string, independentemente da profundidade com que o objeto esteja aninhado em outras matrizes ou objetos.
Argumentos e campos de saída
Quando QueryLanguage definido comoJSONata, os campos de I/O processamento antigos serão desativados (InputPath,Parameters,ResultSelector, ResultPath eOutputPath) e a maioria dos estados receberá dois novos campos: Arguments Output e.
O JSonata fornece uma maneira mais simples de realizar I/O transformações em comparação com os campos usados com o JSONPath. Os recursos do JSONata tornam Arguments e são Output mais capazes do que os cinco campos anteriores de JSONPath. Esses novos nomes de campo também ajudam a simplificar sua ASL e esclarecer o modelo para transmitir e retornar valores.
Os campo Arguments e Output (e outros campos semelhantes, como o ItemSelector do estado Map) aceitarão um objeto JSON, como:
"Arguments": {
"field1": 42,
"field2": "{% jsonata expression %}"
}
Ou você pode usar uma expressão JSONata diretamente, por exemplo:
"Output": "{% jsonata expression %}"
A saída também pode aceitar qualquer tipo de valor JSON, por exemplo, "Output":true ou "Output":42.
Os campos Arguments e Output aceitam somente JSONata, portanto, é inválido usá-los com fluxos de trabalho que usam JSONPath. Por outro lado, InputPath, Parameters, ResultSelector, ResultPath, OutputPath e outros campos JSONPath só são compatíveis com JSONPath, portanto, é inválido usar campos baseados em caminho ao usar JSONata como seu fluxo de trabalho de nível superior ou linguagem de consulta de estado.
Estado de passagem
O resultado opcional em um estado de passagem era tratado anteriormente como a saída de uma tarefa virtual. Com o JSONata selecionado como o fluxo de trabalho ou a linguagem de consulta de estado, agora você pode usar o novo campo Saída.
Estado de escolha
Ao usar o JSONPath, os estados de escolha têm uma entrada Variable e vários caminhos de comparação, como o seguinte NumericLessThanEqualsPath:
# JSONPath choice state sample, with Variable and comparison path
"Check Price": {
"Type": "Choice",
"Default": "Pause",
"Choices": [
{
"Variable": "$.current_price.current_price",
"NumericLessThanEqualsPath": "$.desired_price",
"Next": "Send Notification"
} ],
}
Com JSONata, o estado de escolha tem um Condition onde você pode usar uma expressão JSONata:
# Choice state after JSONata conversion
"Check Price": {
"Type": "Choice",
"Default": "Pause"
"Choices": [
{
"Condition": "{% $current_price <= $states.input.desired_priced %}",
"Next": "Send Notification"
} ]
Observação: variáveis e campos de comparação só estão disponíveis em JSONPath. A condição só está disponível em JSONata.
Exemplos de JSONata
Os exemplos a seguir podem ser criados no Workflow Studio para fazer experiências com JSONata. Você pode criar e executar as máquinas de estado ou usar o estado de teste para transmitir dados e até mesmo modificar a definição da máquina de estado.
Exemplo: entrada e saída
Este exemplo mostra como usar $states.input para usar a entrada de estado e o campo Output para especificar a saída de estado quando você opta pelo JSONata.
{ "Comment": "Input and Output example using JSONata", "QueryLanguage": "JSONata", "StartAt": "Basic Input and Output", "States": { "Basic Input and Output": { "QueryLanguage": "JSONata", "Type": "Succeed", "Output": { "lastName": "{% 'Last=>' & $states.input.customer.lastName %}", "orderValue": "{% $states.input.order.total %}" } } } }
Quando o fluxo de trabalho é executado com o seguinte como entrada:
{ "customer": { "firstName": "Martha", "lastName": "Rivera" }, "order": { "items": 7, "total": 27.91 } }
O estado de teste ou a execução da máquina de estado retornará a seguinte saída JSON:
{
"lastName": "Last=>Rivera",
"orderValue": 27.91
}
Exemplo: filtragem com JSONata
Você pode filtrar seus dados com operadores de caminhoFilterDietProducts com a entrada de amostra a seguir.
Definição da máquina de estado para filtragem com JSONata
{ "Comment": "Filter products using JSONata", "QueryLanguage": "JSONata", "StartAt": "FilterDietProducts", "States": { "FilterDietProducts": { "Type": "Pass", "Output": { "dietProducts": "{% $states.input.products[calories=0] %}" }, "End": true } } }
Entrada de amostra para o teste
{ "products": [ { "calories": 140, "flavour": "Cola", "name": "Product-1" }, { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 160, "flavour": "Orange", "name": "Product-3" }, { "calories": 100, "flavour": "Orange", "name": "Product-4" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }
Resultado do teste da etapa na máquina de estado
{ "dietProducts": [ { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }
Exemplo: Usando a saída do estado anterior em um estado do Mapa
Este exemplo mostra como usar a saída de um estado anterior como entrada para um estado de Mapa com JSonata. O fluxo de trabalho a seguir usa um estado de aprovação para simular uma tarefa que retorna um pedido com uma lista de itens e, em seguida, um estado de Mapa seleciona a matriz de itens dessa saída e itera sobre ela.
Definição de máquina de estado
{ "Comment": "Example: Using previous state output in a Map state with JSONata", "QueryLanguage": "JSONata", "StartAt": "GetOrder", "States": { "GetOrder": { "Type": "Pass", "Output": { "orderId": "{% $states.input.orderId %}", "items": "{% $states.input.items %}" }, "Next": "ProcessItems" }, "ProcessItems": { "Type": "Map", "Items": "{% $states.input.items %}", "ItemProcessor": { "ProcessorConfig": { "Mode": "INLINE" }, "StartAt": "CalculateItemTotal", "States": { "CalculateItemTotal": { "Type": "Pass", "Output": { "name": "{% $states.input.name %}", "total": "{% $states.input.price * $states.input.quantity %}" }, "End": true } } }, "End": true } } }
Nessa definição, o GetOrder estado gera os dados do pedido inalterados. O estado do ProcessItems Mapa é usado "Items": "{% $states.input.items %}" para selecionar a items matriz a partir da saída deGetOrder. Cada iteração recebe um item da matriz e calcula o total do item multiplicando o preço pela quantidade.
Entrada de amostra
{ "orderId": "ORD-1234", "items": [ { "name": "Widget", "price": 4.99, "quantity": 3 }, { "name": "Gadget", "price": 12.50, "quantity": 2 }, { "name": "Bolt", "price": 0.75, "quantity": 10 } ] }
Saída esperada
[
{
"name": "Widget",
"total": 14.97
},
{
"name": "Gadget",
"total": 25
},
{
"name": "Bolt",
"total": 7.5
}
]
Exemplo: nivelamento da saída de estado paralelo
Quando você usa um estado paralelo, ele retorna uma matriz em que cada elemento é a saída de uma ramificação. Com o JSonata, você pode usar o Output campo no estado Paralelo para nivelar ou mesclar esses resultados em um único objeto. Essa abordagem substitui o campo JSONPathResultSelector.
O exemplo a seguir usa um estado paralelo com duas ramificações. Cada ramificação simula uma chamada do GetItem DynamoDB usando um estado Pass. O estado Paralelo usa $merge($states.result) em seu Output campo para mesclar os resultados da ramificação em um único objeto.
Definição de máquina de estado
{ "Comment": "Example: Flattening Parallel state output with JSONata", "QueryLanguage": "JSONata", "StartAt": "GetOrderAndCustomer", "States": { "GetOrderAndCustomer": { "Type": "Parallel", "Output": "{% $merge($states.result) %}", "Branches": [ { "StartAt": "Get Order", "States": { "Get Order": { "Type": "Pass", "Output": { "orderId": "{% $states.input.orderId %}", "orderDate": "2024-11-20", "total": 35.99 }, "End": true } } }, { "StartAt": "Get Customer", "States": { "Get Customer": { "Type": "Pass", "Output": { "customerId": "{% $states.input.customerId %}", "customerName": "Martha Rivera", "email": "martha@example.com" }, "End": true } } } ], "Next": "Done" }, "Done": { "Type": "Succeed" } } }
Entrada de amostra
{ "orderId": "12345", "customerId": "C-100" }
Saída esperada
{
"orderId": "12345",
"orderDate": "2024-11-20",
"total": 35.99,
"customerId": "C-100",
"customerName": "Martha Rivera",
"email": "martha@example.com"
}
A $merge() função combina uma matriz de objetos em um único objeto. Se as ramificações retornarem objetos com chaves sobrepostas, os elementos posteriores da matriz terão precedência. Os resultados das ramificações são ordenados de forma consistente — eles correspondem à ordem da Branches matriz na definição da máquina de estados.
Funções JSONata fornecidas pelo Step Functions
O JSonata contém bibliotecas de funções para funções String, Numeric, Aggregation, Boolean, Array Date/Time, Object e High Order. O Step Functions fornece funções JSONata adicionais que você pode usar em suas expressões JSONata. Essas funções integradas servem como substitutas das funções intrínsecas do Step Functions. As funções intrínsecas só estão disponíveis em estados que usam a linguagem de consulta JSONPath.
Observação: as funções Built-in JSonata que exigem valores inteiros como parâmetros arredondarão automaticamente para baixo quaisquer números não inteiros fornecidos.
$partition: o equivalente em JSONata da função intrínseca States.ArrayPartition para particionar uma matriz grande.
O primeiro parâmetro é a matriz a ser particionada, o segundo parâmetro é um número inteiro representando o tamanho do bloco. O valor retornado será uma matriz bidimensional. O interpretador divide a matriz de entrada em várias matrizes do tamanho especificado pelo tamanho do bloco. O comprimento do último bloco da matriz pode ser menor que o comprimento dos blocos anteriores se o número de itens restantes na matriz for menor que o tamanho do bloco.
"Assign": {
"arrayPartition": "{% $partition([1,2,3,4], $states.input.chunkSize) %}"
}
$range: o equivalente em JSONata da função intrínseca States.ArrayRange para gerar uma matriz de valores.
Essa função usa três argumentos. O primeiro argumento é um valor inteiro que representa o primeiro elemento da nova matriz. O segundo argumento é um número inteiro que representa o elemento final da nova matriz. Já o terceiro argumento é o valor delta do número inteiro para os elementos da nova matriz. O valor de retorno é uma matriz de valores recém-gerada que varia do primeiro argumento ao segundo argumento da função com elementos intermediários ajustados pelo delta. O valor delta pode ser positivo ou negativo, o que incrementará ou diminuirá cada elemento do último até que o valor final seja atingido ou excedido.
"Assign": {
"arrayRange": "{% $range(0, 10, 2) %}"
}
$hash: o equivalente em JSONata da função intrínseca States.Hash para calcular o valor de hash de uma determinada entrada.
Essa função usa dois argumentos. O primeiro argumento é a string de origem a ser codificada. O segundo argumento é uma string que representa o algoritmo de hash para o cálculo de hash. O algoritmo de hash deve ter um dos seguintes valores: "MD5", "SHA-1", "SHA-256", "SHA-384" ou "SHA-512". O valor de retorno é uma string do hash calculado dos dados.
Essa função foi criada porque o JSONata não oferece suporte nativo à capacidade de calcular hashes.
"Assign": {
"myHash": "{% $hash($states.input.content, $hashAlgorithmName) %}"
}
$random: o equivalente em JSONata da função intrínseca States.MathRandom para retornar um número aleatório n em que 0 ≤ n < 1.
A função usa um argumento inteiro opcional representando o valor inicial da função aleatória. Se você usar essa função com o mesmo valor de seed, ela retornará um número idêntico.
Essa função sobrecarregada foi criada porque a função JSONata integrada $random
"Assign": {
"randNoSeed": "{% $random() %}",
"randSeeded": "{% $random($states.input.seed) %}"
}
$uuid: versão JSONata da função intrínseca States.UUID.
A função não aceita argumentos. Ela retorna um UUID v4.
Ela foi criada porque o JSONata não oferece suporte nativo à capacidade de gerar UUIDs.
"Assign": {
"uniqueId": "{% $uuid() %}"
}
$parse: uma função JSONata para desserializar strings JSON.
A função JSON transformado em string como seu único argumento.
O JSONata oferece suporte a essa funcionalidade via $eval; no entanto, $eval não é compatível com os fluxos de trabalho do Step Functions.
"Assign": {
"deserializedPayload": "{% $parse($states.input.json_string) %}"
}