Проверить входную переменную

В этом руководстве объясняется, как проверить входную переменную.

При определении входной переменной рекомендуется убедиться, что пользователь вводит правильное значение. Например, если вы просите пользователя ввести число, проверка того, что он ввёл 1 вместо a подтверждает, что ваш шаг выполняется без ошибок.

Существует два способа проверки входной переменной:

  • Валидация на стороне клиента : с помощью валидации на стороне клиента вы проверяете данные, введённые пользователем, непосредственно на его устройстве. Пользователь получает немедленную обратную связь и может исправить любые ошибки во введённых данных при настройке шага.
  • Проверка на стороне сервера : проверка на стороне сервера позволяет запускать логику на сервере во время проверки, что полезно, когда вам нужно найти информацию, которой нет у клиента, например данные в других системах или базах данных.

Проверка на стороне клиента

Существует два способа реализации проверки на стороне клиента:

  • Для базовой проверки, например проверки того, что виджет содержит меньше определенного количества символов или содержит символ @ , вызовите класс Validation службы Card надстройки Google Workspace.
  • Для надежной проверки, например сравнения значений виджета со значениями других виджетов, вы можете добавить проверку Common Expression Language (CEL) к следующим поддерживаемым виджетам карт с помощью CardService .

Вызов класса Validation

Следующий пример проверяет, что виджет TextInput содержит 10 или менее символов:

Скрипт приложений

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

Для дополнительных вариантов проверки используйте проверку CEL.

Проверка CEL

Валидация на основе Common Expression Language (CEL) обеспечивает мгновенную проверку входных данных без задержек, характерных для проверки на стороне сервера, перекладывая проверки входных значений, не зависящие от поиска данных из других служб, на сторону клиента.

Вы также можете использовать CEL для создания поведения карточки, например, отображения или скрытия виджета в зависимости от результата проверки. Такое поведение полезно для отображения или скрытия сообщения об ошибке, которое помогает пользователям исправить введенные данные.

Создание полной проверки CEL включает в себя следующие компоненты:

  • ExpressionData в карточке: содержит указанную логику проверки и логику срабатывания виджета при выполнении одного из определенных условий.

    • Id : уникальный идентификатор ExpressionData в текущей карте.
    • Expression : строка CEL, определяющая логику проверки (например, "value1 == value2" ).
    • Conditions : список условий, содержащий выбор предопределенных результатов проверки (УСПЕХ или НЕУДАЧА). Условия привязаны к EventAction на стороне виджета через Triggers с общим actionRuleId .
    • EventAction на уровне карты: активирует проверки CEL в карте и связывает поле ExpressionData с виджетами результатов через триггеры после события.
      • actionRuleId : Уникальный идентификатор для этого EventAction .
      • ExpressionDataAction : установите значение START_EXPRESSION_EVALUATION , чтобы указать, что это действие запускает оценку CEL.
      • Trigger : связывает Conditions с EventActions на стороне виджета на основе actionRuleId .
  • EventAction на уровне виджета: управляет поведением виджета результата при выполнении условия успеха или неудачи. Например, виджет результата может быть TextParagraph , содержащим сообщение об ошибке, которое отображается только в случае неудачной проверки.

    • actionRuleId : Соответствует actionRuleId в Trigger на стороне карты.
    • CommonWidgetAction : определяет действия, не требующие оценок, например обновление видимости виджета.
      • UpdateVisibilityAction : действие, которое обновляет состояние видимости виджета (ВИДИМЫЙ или СКРЫТЫЙ).

В следующем примере показано, как реализовать проверку CEL для проверки равенства двух текстовых полей. Если они не равны, выводится сообщение об ошибке.

  • При выполнении условия failCondition (входные данные не равны) виджет сообщения об ошибке становится видимым и отображается.
    Рисунок 1: При выполнении failCondition (входные данные не равны) виджет сообщения об ошибке становится VISIBLE и отображается.
  • При выполнении условия successCondition (входные данные равны) виджет сообщения об ошибке становится СКРЫТЫМ и не отображается.
    Рисунок 2: Если выполняется successCondition (входные данные равны), виджет сообщения об ошибке становится HIDDEN и не отображается.

Вот пример кода приложения и файл манифеста JSON:

Скрипт приложений

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

Файл манифеста 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"
          }
        }
      ]
    }
  }
}

Поддерживаемые виджеты и операции проверки CEL

Виджеты карт, поддерживающие проверку CEL

Следующие виджеты поддерживают проверку CEL:

  • TextInput
  • SelectionInput
  • DateTimePicker

Поддерживаемые операции проверки CEL

  • Арифметические операции
    • + : Складывает два числа int64 , uint64 или double .
    • - : Вычитает два числа int64 , uint64 или double .
    • * : Умножает два числа int64 , uint64 или double .
    • / : Делит два числа int64 , uint64 или double (целочисленное деление).
    • % : Вычисляет модуль двух чисел int64 или uint64 .
    • - : Отменяет число int64 или uint64 .
  • Логические операции:
    • && : выполняет логическую операцию AND над двумя логическими значениями.
    • || : Выполняет логическую операцию OR над двумя булевыми значениями.
    • ! : Выполняет логическую операцию NOT над логическим значением.
  • Операции сравнения:
    • == : проверяет равенство двух значений. Поддерживает числа и списки.
    • != : Проверяет неравенство двух значений. Поддерживает числа и списки.
    • < : Проверяет, меньше ли первое число int64 , uint64 или double второго.
    • <= : Проверяет, меньше ли первое число int64 , uint64 или double или равно второму.
    • > : Проверяет, больше ли первое число int64 , uint64 или double второго.
    • >= : Проверяет, больше ли первое число int64 , uint64 или double или равно второму.
  • Операции со списком:
    • in : Проверяет наличие значения в списке. Поддерживает числа, строки и вложенные списки.
    • size : Возвращает количество элементов в списке. Поддерживает числа и вложенные списки.

Неподдерживаемые сценарии проверки CEL

  • Неправильные размеры аргументов для двоичных операций : Двоичные операции (например, add_int64 и equals) требуют ровно два аргумента. Предоставление другого количества аргументов приведёт к ошибке.
  • Неправильные размеры аргументов для унарных операций : Унарные операции (например, negate_int64 ) требуют ровно один аргумент. Предоставление другого количества аргументов приведёт к ошибке.
  • Неподдерживаемые типы в числовых операциях : Числовые бинарные и унарные операции принимают только числовые аргументы. Предоставление других типов (например, логического) приведёт к ошибке.

Проверка на стороне сервера

С помощью серверной валидации вы можете запустить серверную логику, указав функцию onSaveFunction() в коде шага. Когда пользователь покидает карточку конфигурации шага, onSaveFunction() запускается и позволяет проверить введенные пользователем данные.

Если введенные пользователем данные верны, вернуть saveWorkflowAction .

Если введенные пользователем данные недействительны, верните пользователю карточку конфигурации, которая отображает сообщение об ошибке и объясняет, как устранить ошибку.

Поскольку проверка на стороне сервера выполняется асинхронно, пользователь может не узнать об ошибке ввода, пока не опубликует свой поток.

Каждый проверенный id ввода в файле манифеста должен соответствовать name виджета карты в коде.

Следующий пример проверяет, что введенный пользователем текст содержит знак «@»:

Файл манифеста

В отрывке файла манифеста указана функция onSaveFunction() с именем «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"
          }
        }
      ]
    }
  }
}

Код приложения

Код шага включает функцию onSave() . Она проверяет, содержит ли введённая пользователем строка символ @. Если да, шаг сохраняется. Если нет, возвращается карточка конфигурации с сообщением об ошибке, поясняющим, как её исправить.

Скрипт приложений

/**
 * 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);
  }
}