Memvalidasi variabel input

Panduan ini menjelaskan cara memvalidasi variabel input.

Saat menentukan variabel input, sebagai praktik terbaik, validasi bahwa pengguna memasukkan nilai yang sesuai. Misalnya, jika Anda meminta pengguna memasukkan angka, memverifikasi bahwa mereka memasukkan 1, bukan a, akan memverifikasi bahwa langkah Anda berjalan tanpa error.

Ada dua cara untuk memvalidasi variabel input:

  • Validasi sisi klien: Dengan validasi sisi klien, Anda memverifikasi input pengguna langsung di perangkat mereka. Pengguna menerima masukan langsung dan dapat memperbaiki kesalahan apa pun dalam inputnya saat mengonfigurasi langkah.
  • Validasi sisi server: Validasi sisi server memungkinkan Anda menjalankan logika di server selama validasi, yang berguna saat Anda perlu mencari informasi yang tidak dimiliki klien, seperti data di sistem atau database lain.

Validasi sisi klien

Ada dua cara untuk menerapkan validasi sisi klien:

  • Untuk validasi dasar, seperti memverifikasi apakah widget berisi kurang dari sejumlah karakter tertentu atau berisi simbol @, panggil class Validation layanan Kartu add-on Google Workspace.
  • Untuk validasi yang kuat, seperti membandingkan nilai widget dengan nilai widget lain, Anda dapat menambahkan validasi Common Expression Language (CEL) ke widget kartu yang didukung berikut menggunakan CardService.

Panggil class Validation

Contoh berikut memvalidasi bahwa widget TextInput berisi 10 karakter atau kurang:

Apps Script

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

Untuk opsi validasi tambahan, gunakan validasi CEL.

Validasi CEL

Validasi Common Expression Language (CEL) menawarkan pemeriksaan input instan tanpa latensi validasi sisi server dengan mengalihkan pemeriksaan nilai input yang tidak bergantung pada pencarian data dari layanan lain ke sisi klien.

Anda juga dapat menggunakan CEL untuk membuat perilaku kartu, seperti menampilkan atau menyembunyikan widget, bergantung pada hasil validasi. Perilaku semacam ini berguna untuk menampilkan atau menyembunyikan pesan error yang membantu pengguna mengoreksi input mereka.

Membangun validasi CEL yang lengkap melibatkan komponen berikut:

  • ExpressionData dalam Kartu: Berisi logika validasi dan logika pemicuan widget yang ditentukan saat salah satu Kondisi yang ditentukan terpenuhi.

    • Id: ID unik untuk ExpressionData dalam Kartu saat ini.
    • Expression: String CEL yang menentukan logika validasi (misalnya, "value1 == value2").
    • Conditions: Daftar kondisi yang berisi pilihan hasil validasi yang telah ditentukan sebelumnya (BERHASIL atau GAGAL). Kondisi terikat ke EventAction sisi widget melalui Triggers dengan actionRuleId bersama.
    • EventAction tingkat kartu: Mengaktifkan validasi CEL di Kartu dan mengaitkan kolom ExpressionData ke widget hasil melalui pemicu pasca-peristiwa.
      • actionRuleId: ID unik untuk EventAction ini.
      • ExpressionDataAction: Setel ke START_EXPRESSION_EVALUATION untuk menunjukkan bahwa tindakan ini memulai evaluasi CEL.
      • Trigger: Menghubungkan Conditions ke EventActions sisi Widget berdasarkan actionRuleId.
  • EventAction tingkat widget: Mengontrol perilaku widget hasil saat kondisi berhasil atau gagal terpenuhi. Misalnya, widget hasil dapat berupa TextParagraph yang berisi pesan error yang hanya terlihat saat validasi gagal.

    • actionRuleId: Mencocokkan actionRuleId di Trigger sisi kartu.
    • CommonWidgetAction: Menentukan tindakan yang tidak melibatkan evaluasi, seperti memperbarui visibilitas widget.
      • UpdateVisibilityAction: Tindakan yang memperbarui status visibilitas widget (VISIBLE atau HIDDEN).

Contoh berikut menunjukkan cara menerapkan validasi CEL untuk memeriksa apakah dua input teks sama. Pesan error akan ditampilkan jika keduanya tidak sama.

  • Jika failCondition terpenuhi (input tidak sama), widget pesan error akan disetel ke VISIBLE dan muncul.
    Gambar 1: Saat failCondition terpenuhi (input tidak sama), widget pesan error ditetapkan ke VISIBLE dan muncul.
  • Jika successCondition terpenuhi (input sama), widget pesan error akan disetel ke HIDDEN dan tidak muncul.
    Gambar 2: Saat successCondition terpenuhi (input sama), widget pesan error disetel ke HIDDEN dan tidak muncul.

Berikut adalah contoh kode aplikasi dan file manifes 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();
}

File manifes 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"
          }
        }
      ]
    }
  }
}

Widget dan operasi validasi CEL yang didukung

Widget kartu yang mendukung validasi CEL

Widget berikut mendukung validasi CEL:

  • TextInput
  • SelectionInput
  • DateTimePicker

Operasi validasi CEL yang didukung

  • Operasi aritmatika
    • +: Menambahkan dua angka int64, uint64, atau double.
    • -: Mengurangi dua angka int64, uint64, atau double.
    • *: Mengalikan dua angka int64, uint64, atau double.
    • /: Membagi dua angka int64, uint64, atau double (pembagian bilangan bulat).
    • %: Menghitung modulo dari dua angka int64 atau uint64.
    • -: Mengabaikan angka int64 atau uint64.
  • Operasi logika:
    • &&: Melakukan operasi AND logis pada dua nilai boolean.
    • ||: Melakukan operasi OR logis pada dua nilai boolean.
    • !: Melakukan operasi NOT logis pada nilai boolean.
  • Operasi Perbandingan:
    • ==: Memeriksa apakah dua nilai sama. Mendukung angka dan daftar.
    • !=: Memeriksa apakah dua nilai tidak sama. Mendukung angka dan daftar.
    • <: Memeriksa apakah angka int64, uint64, atau double pertama lebih kecil dari angka kedua.
    • <=: Memeriksa apakah angka int64, uint64, atau double pertama kurang dari atau sama dengan angka kedua.
    • >: Memeriksa apakah angka int64, uint64, atau double pertama lebih besar dari angka kedua.
    • >=: Memeriksa apakah angka int64, uint64, atau double pertama lebih besar dari atau sama dengan angka kedua.
  • Operasi Daftar:
    • in: Memeriksa apakah suatu nilai ada dalam daftar. Mendukung angka, string, dan daftar bertingkat.
    • size: Menampilkan jumlah item dalam daftar. Mendukung angka dan daftar bertingkat.

Skenario validasi CEL yang tidak didukung

  • Ukuran Argumen yang Salah untuk Operasi Biner: Operasi biner (misalnya, add_int64, sama dengan) memerlukan tepat dua argumen. Memberikan jumlah argumen yang berbeda akan memunculkan error.
  • Ukuran Argumen yang Salah untuk Operasi Unary: Operasi unary (misalnya, negate_int64) memerlukan tepat satu argumen. Memberikan jumlah argumen yang berbeda akan memunculkan error.
  • Jenis yang Tidak Didukung dalam Operasi Numerik: Operasi biner dan unary numerik hanya menerima argumen angka. Memberikan jenis lain (misalnya, boolean) akan memunculkan error.

Validasi sisi server

Dengan validasi sisi server, Anda dapat menjalankan logika sisi server dengan menentukan onSaveFunction() dalam kode langkah Anda. Saat pengguna keluar dari kartu konfigurasi langkah, onSaveFunction() akan berjalan dan memungkinkan Anda memverifikasi input pengguna.

Jika input pengguna valid, tampilkan saveWorkflowAction.

Jika input pengguna tidak valid, tampilkan kartu konfigurasi yang menampilkan pesan error kepada pengguna yang menjelaskan cara mengatasi error.

Karena validasi sisi server bersifat asinkron, pengguna mungkin tidak mengetahui kesalahan input hingga mereka memublikasikan alur.

Setiap input yang divalidasi id dalam file manifes harus cocok dengan name widget kartu dalam kode.

Contoh berikut memvalidasi bahwa input teks pengguna menyertakan tanda "@":

File manifes

Cuplikan file manifes menentukan onSaveFunction() bernama "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"
          }
        }
      ]
    }
  }
}

Kode aplikasi

Kode langkah ini mencakup fungsi yang disebut onSave(). Langkah ini memvalidasi bahwa string yang dimasukkan pengguna menyertakan @. Jika ya, langkah ini akan menyimpan langkah alur. Jika tidak, kartu konfigurasi akan ditampilkan dengan pesan error yang menjelaskan cara memperbaiki error tersebut.

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