Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Transformación de datos con JSONata en Step Functions
Con JSONata, obtiene un potente lenguaje de consultas y expresiones de código abierto para seleccionar y transformar los datos de sus flujos de trabajo. Para obtener una breve introducción y una referencia completa de JSonata, consulte JSONata.org la documentación.
Versión de JSonata compatible
Step Functions es compatible con la versión 2.0.6 de JSonata.
En el siguiente video se describen las variables y JSONata en Step Functions con un ejemplo de DynamoDB:
Debe inscribirse para utilizar el lenguaje de consulta y transformación de JSONata para los flujos de trabajo existentes. Al crear un flujo de trabajo en la consola, recomendamos elegir JSONata para la máquina de estado de nivel superior QueryLanguage. Para los flujos de trabajo nuevos o existentes que utilizan JSONPath, la consola ofrece la opción de convertir estados individuales a JSONata.
Tras seleccionar JSONata, los campos del flujo de trabajo pasarán de cinco campos de JSONPath (InputPath, Parameters, ResultSelector, ResultPath y OutputPath) a solo dos campos: Arguments y Output. Además, no utilizará .$ en nombres clave de objetos JSON.
Si es la primera vez que utiliza Step Functions, solo necesita saber que las expresiones de JSONata utilizan la siguiente sintaxis:
Sintaxis de JSONata: "{% <JSONata expression> %}"
Los siguientes ejemplos de código muestran una conversión de JSONPath a 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"
}
}
Con la entrada { "title" : "Doctor" } y la variable customerName asignadas a "María", ambas máquinas de estado producirán el siguiente resultado de JSON:
{
"static": "Hello",
"title": "Doctor",
"name": "María",
"not-evaluated": "$customerName"
}
En el siguiente diagrama, puede ver una representación gráfica que muestra cómo la conversión de JSONPath (izquierda) a JSONata (derecha) reducirá la complejidad de los pasos en sus máquinas de estados:
Puede (opcionalmente) seleccionar y transformar los datos de la entrada de estado en argumentos para enviarlos a la acción integrada. Con JSONata, puede (opcionalmente) seleccionar y transformar los resultados de la acción para asignarlos a las variables y para obtener el estado Output.
Nota: Los pasos Assign y Output se producen en paralelo. Si decide transformar los datos durante la asignación de variables, esos datos transformados no estarán disponibles en el paso Output. Debe volver a aplicar la transformación de JSONata en el paso Output.
QueryLanguage campo
En las definiciones de ASL de su flujo de trabajo, hay un campo QueryLanguage en el nivel superior de la definición de una máquina de estado y en los estados individuales. Al establecer QueryLanguage dentro de estados individuales, puede adoptar JSONata de forma incremental en una máquina de estado existente en lugar de actualizarla de una sola vez.
El campo QueryLanguage se puede definir en "JSONPath" o "JSONata". Si se omite el campo de nivel superior QueryLanguage, el valor predeterminado es "JSONPath". Si un estado contiene un campo de nivel de estado QueryLanguage, Step Functions utilizará el lenguaje de consulta especificado para ese estado. Si el estado no contiene ningún campo QueryLanguage, utilizará el lenguaje de consulta especificado en el campo de nivel superior QueryLanguage.
Escritura de expresiones de JSONata en cadenas JSON
Cuando una cadena del valor de un campo ASL, un campo de objeto JSON o un elemento de matriz JSON esté rodeada de caracteres {% %}, esa cadena se evaluará como JSONata. Tenga en cuenta que la cadena debe empezar con {% sin espacios iniciales y debe terminar con %} sin espacios finales. Si abre o cierra la expresión de forma incorrecta, se producirá un error de validación.
Presentamos algunos ejemplos:
-
"TimeoutSeconds" : "{% $timeout %}" -
"Arguments" : {"field1" : "{% $name %}"}en un estadoTask -
"Items": [1, "{% $two %}", 3]en un estadoMap
No todos los campos de ASL aceptan JSONata. Por ejemplo, el campo Type de cada estado se debe establecer en una cadena constante. Del mismo modo, el campo Resource del estado Task debe ser una cadena constante. El Items campo de Map estado aceptará una matriz JSON, un objeto JSON o una expresión JSonata que debe dar como resultado una matriz u objeto.
Variable reservada: $states
Step Functions define una única variable reservada llamada $states. En los estados de JSONata, se asignan las siguientes estructuras a $states para su uso en las expresiones de 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
}
Al introducir un estado, Step Functions asigna la entrada de estado a $states.input. El valor de $states.input se puede utilizar en todos los campos que acepten expresiones de JSONata. $states.input siempre hace referencia a la entrada de estado original.
Para los estados Task, Parallel, y Map:
-
$states.resultse refiere al resultado bruto de la API o del subflujo de trabajo si se ejecuta correctamente. -
$states.errorOutputhace referencia a la salida de error si la API o el subflujo de trabajo fallaron.$states.errorOutputse puede usar enAssignuOutputdel campoCatch.
Al crear, actualizar o validar la máquina de estado se detectarán los intentos de acceso a $states.result o $states.errorOutput en campos y estados que no son accesibles.
El objeto $states.context brinda a sus flujos de trabajo información sobre su ejecución específica, como StartTime, el token de la tarea y la entrada inicial del flujo de trabajo. Para obtener más información, consulteAcceso a los datos de ejecución desde el objeto Context en Step Functions.
Gestión de errores de expresión
En tiempo de ejecución, la evaluación de la expresión de JSONata puede fallar por varios motivos, como los siguientes:
-
Error de tipo: una expresión, como
{% $x + $y %}, fallará si$xo$yno es un número. -
Incompatibilidad de tipo: una expresión podría evaluarse como un tipo que el campo no aceptará. Por ejemplo, el campo
TimeoutSecondsrequiere una entrada numérica, por lo que la expresión{% $timeout %}fallará si$timeoutdevuelve una cadena. -
Valor fuera de rango: una expresión que produzca un valor que se encuentra fuera del rango aceptable de un campo producirá un error. Por ejemplo, una expresión como
{% $evaluatesToNegativeNumber %}fallará en el campoTimeoutSeconds. -
Error de devolución de un resultado: JSON no puede representar una expresión de valor indefinido, por lo que la expresión
{% $data.thisFieldDoesNotExist %}generaría un error. -
Se ha superado el límite de memoria: una expresión de JSonata que consuma demasiada memoria durante la evaluación fallará y generará un
Expression evaluation memory limit exceedederror. Esto puede ocurrir con expresiones que procesan o transforman grandes cantidades de datos. Para evitar esta limitación, considere la posibilidad de trasladar la transformación de datos a una función Lambda. -
Tiempo de espera de la expresión: una expresión de JSonata que demore más de 1 segundo en evaluarse fallará y generará un error.
Expression evaluation timeoutEsto puede ocurrir con expresiones que contienen bucles infinitos o con operaciones muy costosas. -
Desbordamiento de pila: una expresión de JSonata que supere la profundidad de recursión máxima fallará con un.
Stack overflow errorSi la recursión no termina, asegúrese de que la función tenga un caso base o una condición de terminación correctos. Si la recursión termina pero la pila de llamadas crece demasiado, considere la posibilidad de reescribir la función como recursiva de cola para reducir la profundidad de la pila.
En cada caso, el intérprete generará el error: States.QueryEvaluationError. Los estados Task, Map y Parallel pueden proporcionar un campo Catch para que detecte el error y un campo Retry para volver a intentarlo en caso de error.
Conversión de JSONPath a JSONata
En las siguientes secciones se comparan y explican las diferencias entre el código escrito con JSONPath y JSONata.
No más campos de ruta
ASL requiere que los desarrolladores utilicen versiones Path de los campos, como en TimeoutSecondsPath, para seleccionar un valor de los datos de estado cuando usan JSONPath. Cuando usa JSONata, deja de usar campos Path porque ASL interpreta automáticamente las expresiones de JSONata delimitadas por {% %} para campos que no son de Path, como TimeoutSeconds.
-
Ejemplo heredado de JSONPath:
"TimeoutSecondsPath": "$timeout" -
JSONata:
"TimeoutSeconds": "{% $timeout %}"
Del mismo modo, el Map estado se ItemsPath ha sustituido por el Items campo que acepta una matriz JSON, un objeto JSON o una expresión JSonata que debe dar como resultado una matriz u objeto.
Objetos JSON
ASL utiliza el término plantilla de carga útil para describir un objeto JSON que puede contener expresiones de JSONPath y valores de campo Parameters y ResultSelector. ASL no utilizará el término plantilla de carga útil para JSONata porque la evaluación de JSONata se realiza para todas las cadenas, independientemente de si aparecen por sí solas o dentro de un objeto JSON o una matriz JSON.
No más .$
ASL requiere que añada “.$” a los nombres de los campos en las plantillas de carga útil para usar JSONPath y las funciones intrínsecas. Al especificar "QueryLanguage":"JSONata", ya no se utiliza la convención “.$” para nombres de campo de objetos JSON. En su lugar, delimita las expresiones de JSONata entre caracteres {% %}. Utiliza la misma convención para todos los campos con valores de cadena, independientemente de la profundidad con la que se encuentre el objeto dentro de otras matrices u objetos.
Campos Arguments y Output
Si QueryLanguage se establece enJSONata, los campos de I/O procesamiento antiguos se deshabilitarán (InputPath, ParametersResultSelector, ResultPath yOutputPath) y la mayoría de los estados tendrán dos campos nuevos: Arguments y. Output
JSonata proporciona una forma más sencilla de realizar I/O transformaciones en comparación con los campos utilizados con JSONPath. Las características de JSONata hacen que Arguments y Output sean más capaces que los cinco campos anteriores con JSONPath. Estos nuevos nombres de campo también ayudan a simplificar el ASL y a aclarar el modelo para pasar y devolver valores.
Los campos Arguments y Output (y otros campos similares, como los del estado Map ItemSelector) aceptarán un objeto JSON, como:
"Arguments": {
"field1": 42,
"field2": "{% jsonata expression %}"
}
O bien puede usar una expresión de JSONata directamente, por ejemplo:
"Output": "{% jsonata expression %}"
La salida también puede aceptar cualquier tipo de valor JSON, por ejemplo: "Output":true, "Output":42.
Los campos Arguments y Output solo admiten JSONata, por lo que no es válido utilizarlos con flujos de trabajo que usen JSONPath. Por el contrario, InputPath, Parameters, ResultSelector, ResultPath, OutputPath y otros campos de JSONPath solo se admiten en JSONPath, por lo que no es válido utilizar campos basados en rutas cuando se usa JSONata como flujo de trabajo de nivel superior o lenguaje de consulta de estado.
Estado de paso
El Resultado opcional en un estado Pass se trataba anteriormente como el resultado de una tarea virtual. Con JSONata seleccionado como lenguaje de flujo de trabajo o consulta de estado, ahora puede usar el nuevo campo Output.
Estado Choice
Cuando se utiliza JSONPath, los estados de elección tienen una entrada Variable y numerosas rutas de comparación, como la siguiente 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"
} ],
}
Con JSONata, el estado de elección tiene una Condition en la que puede usar una expresión de JSONata:
# Choice state after JSONata conversion
"Check Price": {
"Type": "Choice",
"Default": "Pause"
"Choices": [
{
"Condition": "{% $current_price <= $states.input.desired_priced %}",
"Next": "Send Notification"
} ]
Nota: Las variables y los campos de comparación solo están disponibles para JSONPath. La condición solo está disponible para JSONata.
Ejemplos de JSONata
Los siguientes ejemplos se pueden crear en Workflow Studio para experimentar con JSONata. Puede crear y ejecutar las máquinas de estado o utilizar el estado Pass para pasar datos e incluso modificar la definición de la máquina de estado.
Ejemplo: entrada y salida
En este ejemplo se muestra cómo utilizar $states.input para usar la entrada de estado y el campo Output para especificar la salida de estado al activar 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 %}" } } } }
Cuando el flujo de trabajo se ejecuta con lo siguiente como entrada:
{ "customer": { "firstName": "Martha", "lastName": "Rivera" }, "order": { "items": 7, "total": 27.91 } }
El estado Test o la ejecución de la máquina de estado devolverá la siguiente salida JSON:
{
"lastName": "Last=>Rivera",
"orderValue": 27.91
}
Ejemplo: filtrar con JSONata
Puede filtrar sus datos con los operadores PathFilterDietProducts con la entrada de ejemplo que aparece a continuación.
Definición de máquina de estado para filtrar con JSONata
{ "Comment": "Filter products using JSONata", "QueryLanguage": "JSONata", "StartAt": "FilterDietProducts", "States": { "FilterDietProducts": { "Type": "Pass", "Output": { "dietProducts": "{% $states.input.products[calories=0] %}" }, "End": true } } }
Ejemplo de entrada para la prueba
{ "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" } ] }
Salida de probar el paso en su máquina de estado
{ "dietProducts": [ { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }
Ejemplo: usar la salida de un estado anterior en un estado de mapa
En este ejemplo, se muestra cómo utilizar la salida de un estado anterior como entrada para un estado del mapa con JSonata. El siguiente flujo de trabajo utiliza un estado de pase para simular una tarea que devuelve un pedido con una lista de elementos y, a continuación, un estado de mapa selecciona la matriz de elementos de esa salida y la recorre en iteración.
Definición de máquina de estados
{ "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 } } }
En esta definición, el GetOrder estado genera los datos del pedido sin cambios. El estado del ProcessItems mapa "Items": "{% $states.input.items %}" se utiliza para seleccionar la items matriz de la salida deGetOrder. Cada iteración recibe un elemento de la matriz y calcula el total del artículo multiplicando el precio por la cantidad.
Ejemplo de entrada
{ "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 } ] }
Salida esperada
[
{
"name": "Widget",
"total": 14.97
},
{
"name": "Gadget",
"total": 25
},
{
"name": "Bolt",
"total": 7.5
}
]
Ejemplo: Aplanamiento de la salida en estado paralelo
Cuando se utiliza un estado paralelo, devuelve una matriz en la que cada elemento es la salida de una rama. Con JSonata, puede usar el Output campo en el estado Paralelo para aplanar o combinar estos resultados en un solo objeto. Este enfoque reemplaza el campo JSONPath. ResultSelector
En el siguiente ejemplo, se utiliza un estado paralelo con dos ramas. Cada rama simula una llamada a GetItem DynamoDB mediante un estado de paso. El estado paralelo utiliza $merge($states.result) en su Output campo para fusionar los resultados de la rama en un único objeto.
Definición de máquina de estados
{ "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" } } }
Ejemplo de entrada
{ "orderId": "12345", "customerId": "C-100" }
Salida esperada
{
"orderId": "12345",
"orderDate": "2024-11-20",
"total": 35.99,
"customerId": "C-100",
"customerName": "Martha Rivera",
"email": "martha@example.com"
}
La $merge() función combina un conjunto de objetos en un único objeto. Si las ramas devuelven objetos con claves superpuestas, los elementos de la matriz posteriores tienen prioridad. Los resultados de las ramas se ordenan de forma coherente: corresponden al orden de la Branches matriz en la definición de la máquina de estados.
Funciones de JSONata proporcionadas por Step Functions
JSonata contiene bibliotecas de funciones para funciones de cadena, numéricas, de agregación, booleanas, de matriz, de objeto y de Date/Time orden superior. Step Functions proporciona funciones de JSONata adicionales que puede usar en sus expresiones de JSONata. Estas funciones integradas sustituyen a las funciones intrínsecas de Step Functions. Las funciones intrínsecas solo están disponibles en los estados que utilizan el lenguaje de consultas JSONPath.
Nota: Las funciones de Built-in JSonata que requieren valores enteros como parámetros redondearán automáticamente a la baja los números no enteros proporcionados.
$partition: equivalente en JSONata de una función intrínseca States.ArrayPartition para particionar una matriz grande.
El primer parámetro es la matriz que se va a particionar, el segundo parámetro es un número entero que representa el tamaño de fragmento. El valor de retorno será una matriz bidimensional. El intérprete divide la matriz de entrada en varias matrices del tamaño especificado por el tamaño del fragmento. La longitud del último fragmento de matriz puede ser menor que la longitud de los fragmentos de matriz anteriores si el número de elementos restantes de la matriz es menor que el tamaño del fragmento.
"Assign": {
"arrayPartition": "{% $partition([1,2,3,4], $states.input.chunkSize) %}"
}
$range: equivalente en JSONata de una función intrínseca States.ArrayRange para generar una matriz de valores.
Esta función toma tres argumentos. El primer argumento es un número entero que representa el primer elemento de la nueva matriz, el segundo argumento un número entero que representa el elemento final de la nueva matriz y el tercer argumento es el número entero del valor delta para los elementos de la nueva matriz. El valor de retorno es una matriz de valores recién generada que va desde el primer argumento de la función hasta el segundo argumento de la función, con los elementos intermedios ajustados por el delta. El valor delta puede ser positivo o negativo, lo que incrementará o disminuirá cada elemento desde el último hasta alcanzar o superar el valor final.
"Assign": {
"arrayRange": "{% $range(0, 10, 2) %}"
}
$hash: equivalente en JSONata de la función intrínseca States.Hash para calcular el valor hash de una entrada determinada.
Esta función toma dos argumentos. El primer argumento es la cadena de origen a la que se va a aplicar la función de hash. El segundo argumento es una cadena que representa el algoritmo de hash para el cálculo del hash. El algoritmo de hash debe tener uno de los siguientes valores: "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512". El valor de retorno es una cadena del hash calculado de los datos.
Esta función se creó porque JSONata no admite de forma nativa la capacidad de calcular hashes.
"Assign": {
"myHash": "{% $hash($states.input.content, $hashAlgorithmName) %}"
}
$random: equivalente en JSONata de la función intrínseca States.MathRandom para devolver un número aleatorio n donde 0 ≤ n < 1.
La función toma un argumento entero opcional que representa el valor de inicio de la función aleatoria. Si utiliza esta función con el mismo valor de inicio, devolverá un número idéntico.
Esta función sobrecargada se creó porque la función de JSONata integrada $random
"Assign": {
"randNoSeed": "{% $random() %}",
"randSeeded": "{% $random($states.input.seed) %}"
}
$uuid: versión de JSONata de la función intrínseca States.UUID.
La función no toma argumentos. Esta función devuelve un UUID v4.
Esta función se creó porque JSONata no admite de forma nativa la capacidad de generar UUID.
"Assign": {
"uniqueId": "{% $uuid() %}"
}
$parse: función de JSONata para deserializar cadenas JSON.
La función toma un JSON representado en forma de cadena como único argumento.
JSONata admite esta funcionalidad a través de $eval, sin embargo, $eval no es compatible con los flujos de trabajo de Step Functions.
"Assign": {
"deserializedPayload": "{% $parse($states.input.json_string) %}"
}