Valida una variable de entrada

En esta guía, se explica cómo validar una variable de entrada.

Cuando definas una variable de entrada, como práctica recomendada, valida que el usuario ingrese un valor adecuado. Por ejemplo, si le pides al usuario que ingrese un número, verificar que ingrese 1 en lugar de a verifica que tu paso se ejecute sin errores.

Existen dos formas de validar una variable de entrada:

  • Validación del cliente: Con la validación del cliente, verificas la entrada del usuario directamente en su dispositivo. El usuario recibe comentarios inmediatos y puede corregir cualquier error en su entrada mientras configura el paso.
  • Validación del servidor: La validación del servidor te permite ejecutar lógica en el servidor durante la validación, lo que resulta útil cuando necesitas buscar información que el cliente no tiene, como datos en otros sistemas o bases de datos.

Validación del cliente

Existen dos formas de implementar la validación del cliente:

  • Para la validación básica, como verificar que un widget contenga menos de una cierta cantidad de caracteres o que contenga el símbolo @, invoca la clase Validation del servicio Card del complemento de Google Workspace.
  • Para una validación sólida, como comparar valores de widgets con otros valores de widgets, puedes agregar validación de Common Expression Language (CEL) a los siguientes widgets de tarjetas compatibles con CardService.

Invoca la clase Validation

En el siguiente ejemplo, se valida que un widget de TextInput contenga 10 caracteres o menos:

Apps Script

const validation = CardService.newValidation().setCharacterLimit('10').setInputType(
    CardService.InputType.TEXT);

Para obtener opciones de validación adicionales, usa la validación de CEL.

Validación de CEL

La validación del Common Expression Language (CEL) ofrece verificaciones instantáneas de entrada sin la latencia de la validación del servidor, ya que descarga las verificaciones de valores de entrada que no dependen de la búsqueda de datos de otros servicios en el cliente.

También puedes usar CEL para crear comportamientos de tarjetas, como mostrar u ocultar un widget según el resultado de la validación. Este tipo de comportamiento es útil para mostrar u ocultar un mensaje de error que ayude a los usuarios a corregir sus entradas.

La creación de una validación de CEL completa implica los siguientes componentes:

  • ExpressionData en la tarjeta: Contiene la lógica de validación especificada y la lógica de activación de widgets cuando se cumple una de las condiciones definidas.

    • Id: Es un identificador único del ExpressionData dentro de la tarjeta actual.
    • Expression: Es la cadena de CEL que define la lógica de validación (p.ej., "value1 == value2").
    • Conditions: Es una lista de condiciones que contiene una selección de resultados de validación predefinidos (SUCCESS o FAILURE). Las condiciones se vinculan al EventAction del widget a través de Triggers con un actionRuleId compartido.
    • EventAction a nivel de la tarjeta: Activa las validaciones de CEL en la tarjeta y asocia el campo ExpressionData a los widgets de resultados a través de activadores posteriores al evento.
      • actionRuleId: Es el ID único de este EventAction.
      • ExpressionDataAction: Se establece en START_EXPRESSION_EVALUATION para indicar que esta acción inicia la evaluación de CEL.
      • Trigger: Conecta el Conditions al EventActions del lado del widget según el actionRuleId.
  • EventAction a nivel del widget: Controla el comportamiento del widget de resultados cuando se cumple la condición de éxito o de falla. Por ejemplo, un widget de resultado puede ser un TextParagraph que contiene un mensaje de error que solo se hace visible cuando falla la validación.

    • actionRuleId: Coincide con el actionRuleId en el Trigger del lado de la tarjeta.
    • CommonWidgetAction: Define acciones que no implican evaluaciones, como actualizar la visibilidad de un widget.
      • UpdateVisibilityAction: Es una acción que actualiza el estado de visibilidad de un widget (VISIBLE o HIDDEN).

En el siguiente ejemplo, se muestra cómo implementar la validación de CEL para verificar si dos entradas de texto son iguales. Si no son iguales, se muestra un mensaje de error.

  • Cuando se cumple la condición de falla (las entradas no son iguales), el widget de mensaje de error se establece en VISIBLE y aparece.
    Figura 1: Cuando se cumple la condición failCondition (las entradas no son iguales), el widget de mensaje de error se establece en VISIBLE y aparece.
  • Cuando se cumple la condición de éxito (las entradas son iguales), el widget de mensaje de error se establece como HIDDEN y no aparece.
    Figura 2: Cuando se cumple la condición successCondition (las entradas son iguales), el widget de mensaje de error se establece en HIDDEN y no aparece.

Estos son el código de la aplicación de ejemplo y el archivo de manifiesto JSON:

Apps Script

function onConfig() {

  // Create a Card
  let card = CardService.newCardBuilder();

  const textInput_1 = CardService.newTextInput()
    .setTitle("Input number 1")
    .setFieldName("value1"); // FieldName's value must match a corresponding ID defined in the inputs[] array in the manifest file.
  const textInput_2 = CardService.newTextInput()
    .setTitle("Input number 2")
    .setFieldName("value2"); // FieldName's value must match a corresponding ID defined in the inputs[] array in the manifest file.
  let sections = CardService.newCardSection()
    .setHeader("Two number equals")
    .addWidget(textInput_1)
    .addWidget(textInput_2);

  // CEL Validation

  // Define Conditions
  const condition_success = CardService.newCondition()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID")
    .setExpressionDataCondition(
      CardService.newExpressionDataCondition()
      .setConditionType(
        CardService.ExpressionDataConditionType.EXPRESSION_EVALUATION_SUCCESS));
  const condition_fail = CardService.newCondition()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID")
    .setExpressionDataCondition(
      CardService.newExpressionDataCondition()
      .setConditionType(
        CardService.ExpressionDataConditionType.EXPRESSION_EVALUATION_FAILURE));

  // Define Card-side EventAction
  const expressionDataAction = CardService.newExpressionDataAction()
    .setActionType(
      CardService.ExpressionDataActionType.START_EXPRESSION_EVALUATION);
  // Define Triggers for each Condition respectively
  const trigger_success = CardService.newTrigger()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID");
  const trigger_failure = CardService.newTrigger()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID");

  const eventAction = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_EVALUATION_RULE_ID")
    .setExpressionDataAction(expressionDataAction)
    .addPostEventTrigger(trigger_success)
    .addPostEventTrigger(trigger_failure);

  // Define ExpressionData for the current Card
  const expressionData = CardService.newExpressionData()
    .setId("expData_id")
    .setExpression("value1 == value2") // CEL expression
    .addCondition(condition_success)
    .addCondition(condition_fail)
    .addEventAction(eventAction);
  card = card.addExpressionData(expressionData);

  // Create Widget-side EventActions and a widget to display error message
  const widgetEventActionFail = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID")
    .setCommonWidgetAction(
      CardService.newCommonWidgetAction()
      .setUpdateVisibilityAction(
        CardService.newUpdateVisibilityAction()
        .setVisibility(
          CardService.Visibility.VISIBLE)));
  const widgetEventActionSuccess = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID")
    .setCommonWidgetAction(
      CardService.newCommonWidgetAction()
      .setUpdateVisibilityAction(
        CardService.newUpdateVisibilityAction()
        .setVisibility(
          CardService.Visibility.HIDDEN)));
  const errorWidget = CardService.newTextParagraph()
    .setText("The first and second value must match.")
    .setVisibility(CardService.Visibility.HIDDEN) // Initially hidden
    .addEventAction(widgetEventActionFail)
    .addEventAction(widgetEventActionSuccess);
  sections = sections.addWidget(errorWidget);

  card = card.addSection(sections);
  // Build and return the Card
  return card.build();
}

Archivo de manifiesto JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "CEL validation example",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/calculator_search/v1/web-24dp/logo_calculator_search_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "CEL Demo",
          "description": "Demonstrates CEL Validation",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "The first number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              },
              {
                "id": "value2",
                "description": "The second number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              }
            ],
            "onConfigFunction": "onConfig",
            "onExecuteFunction": "onExecute"
          }
        }
      ]
    }
  }
}

Widgets y operaciones de validación de CEL compatibles

Widgets de tarjetas que admiten la validación de CEL

Los siguientes widgets admiten la validación de CEL:

  • TextInput
  • SelectionInput
  • DateTimePicker

Operaciones de validación de CEL admitidas

  • Operaciones aritméticas
    • +: Suma dos números int64, uint64 o double.
    • -: Resta dos números int64, uint64 o double.
    • *: Multiplica dos números int64, uint64 o double.
    • /: Divide dos números int64, uint64 o double (división de números enteros).
    • %: Calcula el módulo de dos números int64 o uint64.
    • -: Niega un número int64 o uint64.
  • Operaciones lógicas:
    • &&: Realiza una operación AND lógica en dos valores booleanos.
    • ||: Realiza una operación OR lógica en dos valores booleanos.
    • !: Realiza una operación NOT lógica en un valor booleano.
  • Operaciones de comparación:
    • ==: Verifica si dos valores son iguales. Admite números y listas.
    • !=: Verifica si dos valores no son iguales. Admite números y listas.
    • <: Comprueba si el primer número int64, uint64 o double es menor que el segundo.
    • <=: Verifica si el primer número int64, uint64 o double es menor o igual que el segundo.
    • >: Comprueba si el primer número int64, uint64 o double es mayor que el segundo.
    • >=: Verifica si el primer número int64, uint64 o double es mayor o igual que el segundo.
  • Operaciones de lista:
    • in: Verifica si un valor está presente en una lista. Admite números, cadenas y listas anidadas.
    • size: Devuelve la cantidad de elementos de una lista. Admite números y listas anidadas.

Situaciones de validación de CEL no admitidas

  • Tamaños de argumentos incorrectos para operaciones binarias: Las operaciones binarias (por ejemplo, add_int64, igual a) requieren exactamente dos argumentos. Si se proporciona una cantidad diferente de argumentos, se generará un error.
  • Tamaños de argumentos incorrectos para operaciones unarias: Las operaciones unarias (por ejemplo, negate_int64) requieren exactamente un argumento. Si se proporciona una cantidad diferente de argumentos, se generará un error.
  • Tipos no admitidos en operaciones numéricas: Las operaciones numéricas binarias y unarias solo aceptan argumentos numéricos. Si se proporcionan otros tipos (por ejemplo, booleanos), se generará un error.

Validación del servidor

Con la validación del servidor, puedes ejecutar la lógica del servidor especificando onSaveFunction() en el código de tu paso. Cuando el usuario sale de la tarjeta de configuración del paso, se ejecuta onSaveFunction() y te permite verificar la entrada del usuario.

Si la entrada del usuario es válida, devuelve saveWorkflowAction.

Si la entrada del usuario no es válida, devuelve una tarjeta de configuración que muestre un mensaje de error al usuario en el que se explique cómo resolverlo.

Dado que la validación del servidor es asíncrona, es posible que el usuario no sepa sobre el error de entrada hasta que publique su flujo.

Cada id de entrada validado en el archivo de manifiesto debe coincidir con un name de widget de tarjeta en el código.

En el siguiente ejemplo, se valida que la entrada de texto del usuario incluya el signo "@":

Archivo de manifiesto

El fragmento del archivo de manifiesto especifica un onSaveFunction() llamado "onSave":

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Server-side validation example",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/calculator_search/v1/web-24dp/logo_calculator_search_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "Calculate",
          "description": "Asks the user for an email address",
          "workflowAction": {
            "inputs": [
              {
                "id": "email",
                "description": "email address",
                "cardinality": "SINGLE",
                "required": true,
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfigCalculate",
            "onExecuteFunction": "onExecuteCalculate",
            "onSaveFunction": "onSave"
          }
        }
      ]
    }
  }
}

Código de la aplicación

El código del paso incluye una función llamada onSave(). Valida que una cadena ingresada por el usuario incluya @. Si es así, guarda el paso del flujo. De lo contrario, muestra una tarjeta de configuración con un mensaje de error que explica cómo corregirlo.

Apps Script

/**
 * Validates user input asynchronously when the user
 * navigates away from a step's configuration card.
*/
function onSave(event) {

  // "email" matches the input ID specified in the manifest file.
  var email = event.workflow.actionInvocation.inputs["email"];

  // Validate that the email address contains an "@" sign:
  if(email.includes("@")) {

  // If successfully validated, save and proceed.
    return {
      "hostAppAction" : {
        "workflowAction" : {
          "saveWorkflowAction" : {}
        }
      }
    };

  // If the input is invalid, return a card with an error message
  } else {

var card = {
    "sections": [
      {
        "header": "Collect Email",
        "widgets": [
          {
            "textInput": {
              "name": "email",
              "label": "email address",
              "hostAppDataSource" : {
                "workflowDataSource" : {
                  "includeVariables" : true
                }
              }
            }
          },
          {
            "textParagraph": {
              "text": "<b>Error:</b> Email addresses must include the '@' sign.",
              "maxLines": 1
            }
          }
        ]
      }
    ]
  };
  return pushCard(card);
  }
}