이 가이드에서는 입력 변수를 검증하는 방법을 설명합니다.
입력 변수를 정의할 때는 사용자가 적절한 값을 입력하는지 확인하는 것이 좋습니다. 예를 들어 사용자에게 숫자를 입력하라고 요청하는 경우 a 대신 1을 입력하는지 확인하면 단계가 오류 없이 실행되는지 확인할 수 있습니다.
입력 변수를 검증하는 방법에는 두 가지가 있습니다.
- 클라이언트 측 유효성 검사: 클라이언트 측 유효성 검사를 사용하면 사용자의 기기에서 직접 사용자의 입력을 확인할 수 있습니다. 사용자는 즉시 피드백을 받고 단계를 구성하는 동안 입력의 오류를 수정할 수 있습니다.
- 서버 측 검증: 서버 측 검증을 사용하면 검증 중에 서버에서 로직을 실행할 수 있습니다. 이는 클라이언트에 없는 정보(예: 다른 시스템이나 데이터베이스의 데이터)를 조회해야 하는 경우에 유용합니다.
클라이언트 측 유효성 검사
클라이언트 측 유효성 검사를 구현하는 방법에는 두 가지가 있습니다.
- 위젯에 특정 수 미만의 문자가 포함되어 있는지 또는
@기호가 포함되어 있는지 확인하는 등의 기본 유효성 검사의 경우 Google Workspace 부가기능의 카드 서비스의Validation클래스를 호출합니다. - 위젯 값을 다른 위젯 값과 비교하는 등 강력한 검증을 위해
CardService를 사용하여 지원되는 다음 카드 위젯에 Common Expression Language (CEL) 검증을 추가할 수 있습니다.
Validation 클래스 호출
다음 예에서는 TextInput 위젯에 10자 이하의 문자가 포함되어 있는지 확인합니다.
Apps Script
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: 사전 정의된 검증 결과 (SUCCESS 또는 FAILURE)의 선택 항목이 포함된 조건 목록입니다. 조건은 공유된actionRuleId를 사용하여Triggers를 통해 위젯 측EventAction에 연결됩니다.- 카드 수준
EventAction: 카드에서 CEL 유효성 검사를 활성화하고 이벤트 후 트리거를 통해ExpressionData필드를 결과 위젯에 연결합니다.actionRuleId: 이EventAction의 고유 ID입니다.ExpressionDataAction: 이 작업이 CEL 평가를 시작함을 나타내려면START_EXPRESSION_EVALUATION로 설정합니다.Trigger:actionRuleId에 따라Conditions을 위젯 측EventActions에 연결합니다.
위젯 수준
EventAction: 성공 또는 실패 조건이 충족될 때 결과 위젯의 동작을 제어합니다. 예를 들어 결과 위젯은 유효성 검사에 실패할 때만 표시되는 오류 메시지가 포함된TextParagraph일 수 있습니다.actionRuleId: 카드 측Trigger의actionRuleId와 일치합니다.CommonWidgetAction: 위젯 표시 상태 업데이트와 같이 평가가 포함되지 않는 작업을 정의합니다.UpdateVisibilityAction: 위젯의 표시 상태 (VISIBLE 또는 HIDDEN)를 업데이트하는 작업입니다.
다음 예에서는 두 텍스트 입력이 동일한지 확인하기 위해 CEL 유효성 검사를 구현하는 방법을 보여줍니다. 같지 않으면 오류 메시지가 표시됩니다.
-
그림 1: failCondition이 충족되면 (입력이 같지 않음) 오류 메시지 위젯이VISIBLE로 설정되고 표시됩니다. -
그림 2: successCondition이 충족되면 (입력이 동일함) 오류 메시지 위젯이HIDDEN로 설정되고 표시되지 않습니다.
다음은 애플리케이션 코드와 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(); } 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 검증을 지원합니다.
TextInputSelectionInputDateTimePicker
지원되는 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와 일치해야 합니다.
다음 예에서는 사용자 텍스트 입력에 '@' 기호가 포함되어 있는지 확인합니다.
매니페스트 파일
매니페스트 파일 발췌문은 'onSave'라는 onSaveFunction()를 지정합니다.
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()라는 함수가 포함되어 있습니다. 사용자가 입력한 문자열에 @가 포함되어 있는지 확인합니다. 포함되어 있으면 흐름 단계를 저장합니다. 그렇지 않으면 오류를 수정하는 방법을 설명하는 오류 메시지가 포함된 구성 카드를 반환합니다.
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"]; // Base card. var card = { "sections": [ { "header": "Collect Email", "widgets": [ { "textInput": { "name": "email", "label": "email address", "hostAppDataSource" : { "workflowDataSource" : { "includeVariables" : true } } } } ] } ] }; // Validate that the email address contains an "@" sign: if(email.includes("@")) { // If successfully validated, save and proceed. // To clear any previous validation errors, push an updated // card that doesn't include an error message. return { "action": { "navigations": [{ "pushCard": card }] }, "hostAppAction" : { "workflowAction" : { "saveWorkflowAction" : {} } } }; // If the input is invalid, return a card with an error message // and a validation error action. } else { // Add an error message to the card. card.sections[0].widgets.push({ "textParagraph": { "text": "<b>Error:</b> Email addresses must include the '@' sign.", "maxLines": 1 } }); return { "action": { "navigations": [{ "pushCard": card }] }, "hostAppAction": { "workflowValidationErrorAction": { "severity": "CRITICAL" } } }; } }