Represent complex data with a custom resource

This guide explains how to define custom resources for Google Workspace Flows.

Custom resources are custom data structures that you can define to group multiple variables together. For example, to create a CRM lead, pass a custom resource containing an email address, street address, and name.

These are the two ways to define custom resources:

  • As a reference: When you output a custom resource as a reference, you return the custom resource by its ID instead of the full custom resource object. This improves performance by reducing the data transferred between flow steps. When data requires secondary lookups, returning its ID is useful for performing those lookups.
  • As a value: Use this method when the data must be retrieved during execution, or when the custom resource is small and doesn't contain sensitive data.

Output a custom resource as a reference

By outputting a custom resource as a reference, you can return the custom resource by its ID instead of the full custom resource object. If a custom resource is large or complex, passing only the ID improves performance by reducing the data transferred between flow steps.

To output a custom resource as a reference, edit the step's manifest file and code.

Edit the manifest file

In the manifest file:

  1. Specify a workflowResourceDefinitions and assign it an id, a fields[] array, and a providerFunction. The workflowResourceDefinitions is a structure that defines data types and contents of the custom resource.

  2. Within the fields[] array, you specify the individual fields that make up the custom resource, in this example called field_1 and field_2.

  3. The providerFunction's value must match the name of a function in the step's code. The providerFunction retrieves actual custom resource content when needed.

    JSON

    {
        "workflowResourceDefinitions": [
            {
                "id": "resource_id",
                "name": "Custom Resource",
                "fields": [
                    {
                        "selector": "field_1",
                        "name": "Field 1",
                        "dataType": {
                            "basicType": "STRING"
                        }
                    },
                    {
                        "selector": "field_2",
                        "name": "Field 2",
                        "dataType": {
                            "basicType": "STRING"
                        }
                    }
                ],
                "providerFunction": "onMessageResourceFunction"
            }
        ]
    }
    
  4. In outputs[], specify an output variable that returns a dynamic set of output variables. The output variable has a dataType with the property resourceType. The value of cardinality must be SINGLE.

    JSON

    "outputs": [{
            "id": "resource_data",
            "description": "Resource Data",
            "cardinality": "SINGLE",
            "dataType": {
              "resourceType": { "workflowResourceDefinitionId": "resource_id" }
            }
          }]
    

Here's a complete manifest file that defines a custom resource:

JSON

{
    "timeZone": "America/Los_Angeles",
    "exceptionLogging": "STACKDRIVER",
    "runtimeVersion": "V8",
    "addOns": {
        "common": {
            "name": "Calculator",
            "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": "getResourceData",
                    "state": "ACTIVE",
                    "name": "Get Resource by ID",
                    "description": "Get Resource by ID",
                    "workflowAction": {
                        "outputs": [
                            {
                                "id": "resource_data",
                                "description": "Resource Data",
                                "cardinality": "SINGLE",
                                "dataType": {
                                    "resourceType": {
                                        "workflowResourceDefinitionId": "resource_id"
                                    }
                                }
                            }
                        ],
                        "onConfigFunction": "onConfigResourceFunction",
                        "onExecuteFunction": "onExecuteResourceFunction"
                    }
                }
            ],
            "workflowResourceDefinitions": [
                {
                    "id": "resource_id",
                    "name": "Custom Resource",
                    "fields": [
                        {
                            "selector": "field_1",
                            "name": "Field 1",
                            "dataType": {
                                "basicType": "STRING"
                            }
                        },
                        {
                            "selector": "field_2",
                            "name": "Field 2",
                            "dataType": {
                                "basicType": "STRING"
                            }
                        }
                    ],
                    "providerFunction": "onMessageResourceFunction"
                }
            ]
        }
    }
}

Edit the code

In the application code:

  1. Implement the providerFunction, called onMessageResourceFunction() in this example, which retrieves custom resource content when needed. It takes the input e which is the step's event object JSON payload, and from it sets the custom resource ID.

    Apps Script

    function onMessageResourceFunction(e) {
      var resource_id = e.workflow.resourceRetrieval.resourceReference.resourceId;
      var field_1 = ...;
      var field_2 = ...;
    
      return {
        "hostAppAction": {
          "workflowAction": {
            "resourceRetrievedAction": {
              "resourceJson": JSON.stringify({
                "field_1": field_1,
                "field_2": field_2,
              })
            }
          }
        }
      };
    }
    
  2. The provider function must return the value of the custom resource by retrieving it with an appropriate mechanism, like calling an API or reading a database.

  3. To retrieve and return a custom resource by its ID, return it as returnOutputVariablesAction, as shown in onExecuteResourceFunction().

    Apps Script

    function onExecuteResourceFunction(e) {
      var resource_id = e.workflow.resourceRetrieval.resourceReference.resourceId;
      return {
        "hostAppAction": {
          "workflowAction": {
            "returnOutputVariablesAction": {
              "variableValues": [{
                "variableId": "resource_data",
                "variableData": {
                  "resourceReferences" : [ resource_id ]
                }
              }]
            }
          }
        }
      };
    }
    

Here's a complete example:

Apps Script

function onMessageResourceFunction(e) {
  var resource_id = e.workflow.resourceRetrieval.resourceReference.resourceId;
  var field_1 = ...;
  var field_2 = ...;

  return {
    "hostAppAction": {
      "workflowAction": {
        "resourceRetrievedAction": {
          "resourceJson": JSON.stringify({
            "field_1": field_1,
            "field_2": field_2,
          })
        }
      }
    }
  };
}

function onExecuteResourceFunction(e) {
  var resource_id = e.workflow.resourceRetrieval.resourceReference.resourceId;
  return {
    "hostAppAction": {
      "workflowAction": {
        "returnOutputVariablesAction": {
          "variableValues": [{
            "variableId": "resource_data",
            "variableData": {
              "resourceReferences" : [ resource_id ]
            }
          }]
        }
      }
    }
  };
}

Output a custom resource as a value

When you output a custom resource as a reference, you return the custom resource by its ID instead of the full custom resource object. If you need to pass the entire resource object, you can with resourceValues.

In resourceValues, you define the output of a step.

To output a custom resource as a value, edit the step's manifest file and code.

Edit the manifest file

In the manifest file:

  1. Specify a workflowResourceDefinitions and assign it an id.The workflowResourceDefinitions is a structure that defines data types and contents of the custom resource. Within workflowResourceDefinitions, you specify the individual fields that make up the custom resource, in this example called field_1 and field_2.

  2. Specify a providerFunction whose value is the name of a function in the step's code. The providerFunction retrieves actual custom resource content when needed.

    JSON

    {
        "workflowResourceDefinitions": [
            {
                "id": "resource_id",
                "name": "Custom Resource",
                "fields": [
                    {
                        "selector": "field_1",
                        "name": "Field 1",
                        "dataType": {
                            "basicType": "STRING"
                        }
                    },
                    {
                        "selector": "field_2",
                        "name": "Field 2",
                        "dataType": {
                            "basicType": "STRING"
                        }
                    }
                ],
                "providerFunction": "onExecuteResourceAsValuesFunction"
            }
        ]
    }
    
  3. In outputs[], specify an output variable that returns resourceValues. The value of cardinality must be SINGLE.

    JSON

    {
        "outputs": [
            {
                "id": "resource_data",
                "description": "Resource Data",
                "cardinality": "SINGLE",
                "dataType": {
                    "resourceValues": {
                        "value1": "value one"
                    }
                }
            }
        ]
    }
    

Here's a complete manifest file which defines a custom resource:

JSON

{
    "timeZone": "America/Los_Angeles",
    "exceptionLogging": "STACKDRIVER",
    "runtimeVersion": "V8",
    "addOns": {
        "common": {
            "name": "Calculator",
            "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": "getResourceData",
                    "state": "ACTIVE",
                    "name": "Get Resource by ID",
                    "description": "Get Resource by ID",
                    "workflowAction": {
                        "outputs": [
                            {
                                "id": "resource_data",
                                "description": "Resource Data",
                                "cardinality": "SINGLE",
                                "dataType": {
                                    "resourceValues": {
                                        "value1": "value one"
                                    }
                                }
                            }
                        ],
                        "onConfigFunction": "onConfigResourceFunction",
                        "onExecuteFunction": "onExecuteResourceFunction"
                    }
                }
            ],
            "workflowResourceDefinitions": [
                {
                    "id": "resource_id",
                    "name": "Custom Resource",
                    "fields": [
                        {
                            "selector": "field_1",
                            "name": "Field 1",
                            "dataType": {
                                "basicType": "STRING"
                            }
                        },
                        {
                            "selector": "field_2",
                            "name": "Field 2",
                            "dataType": {
                                "basicType": "STRING"
                            }
                        }
                    ],
                    "providerFunction": "onExecuteResourceAsValuesFunction"
                }
            ]
        }
    }
}

Edit the code

In the application code, implement the providerFunction, called onExecuteResourceAsValuesFunction() in this example, which defines and returns the custom resource as JSON, here abstracted as resourceJSON:

Apps Script

function onExecuteResourceAsValuesFunction() {
  var field_1 = "value 1";
  var field_2 = "value 2";
  var resourceJSON = JSON.stringify({
    "field_1": field_1,
    "field_2": field_2,
  });
  return {
    "hostAppAction": {
      "workflowAction": {
        "returnOutputVariablesAction": {
          "variableValues": [{
            "variableId": "resource_data",
            "variableData": {
              "resourceValues" : [ resourceJSON ]
            }
          }]
        }
      }
    }
  };
}