Metadata Methods

Metadata methods are helper methods that supplement the Events and Actions in your Connector. Some uses of Metadata methods include:
* Generating the arrays that populate dynamic dropdowns
* Building dynamic input and output schemas that include users' custom fields
* Containing code that will be re-used in several methods
* Executing branches from main methods
* Executing complex loops
* Error handling

Metadata methods only have one section, the Core array where you declare the set of modules that execute the method. Since they do not appear in the UI, they do not require parameters, input, and output schemas.

Metadata methods are helpful because they can unload work off of other modules, meaning that data passing from the Event/Action method into the metadata method is crucial. At its most fundamental level, any field that is an output of the Event/Action method that is calling the metadata method can be called with the Mustache reference {{input.field_name}}. For more specific cases, such as metadata method classes and context passing, read on.

Metadata Method Classes

Metadata methods can serve many different use cases, but sometimes special classes must be added to a metadata to allow certain kinds of functionality to run smoothly. The three types of metadata methods that require an additional metadata method class are iterative metadata methods, list.reduce, and all error handling metadata methods. These classes must be added at the top level of a metadata method object, before any inputs/outputs it accepts. Read on for more information about each type.

Iterations

Many commonly used modules that are collection-based require an input that acts as its own FLO (FLO input), which handles functionality that operates on each element. Referencing the Module Library documentation for each module should indicate which modules will require a FLO input or not. For these FLO inputs, you must specify "_type" as "flo". You then specify what this FLO will do by providing a reference to a metadata method's name that will act as the FLO you want operating on each element.

Example:

{
"brick": "list.map",
"input": {
"collection": "{{prevData.array}}",
"concurrency": 4,
"flo": {
"_type": "flo",
"_value": "[metadataMethodID]"
}
}
}

After marking the FLO input in your Event/Action method, you then need to create a flag in the accompanying metadata method to indicate its use as an iteration method, which has consequences for how inputs are mapped into the function. Inside the method declaration (when you click the name of your metadata method on the left menu), the "variant" flag needs to be inserted at the top level of the metadata object.

Example:

{
"name": "[metadataMethodName]",
"kind": "metadata",
"variant": {
"_type": "object",
"_key": "[itemName]",
"_array": false
},
"zebricks": [
{
//modules you create will go here
}
]
}

If you want to reference the item of the current iteration, you use {{itemName.path_goes_here}}. When declaring the key to reference the current iteration, you can also choose to declare what the type of the item is (optional "_type" key), whether it's an array or not (optional "_array" key), and the defaultValue it should be if undefined or null (optional "_defaultValue" key).

List.reduce (memo)

For methods like List.reduce, which use a memo property, you declare a memo property at the same namespace as the variant property. This memo property can be used to keep track of state, as the list is being reduced. It defaults to an empty object, but you may change this to be any other value. Memo may also be used with other class objects, for example:

{
"name": "metadata_method",
"variant": {
"_type": "object",
"_key": "item",
"_array": false
},
"memo": {
"_type": "object",
"_array": false
},
"zebricks": [
{
// modules you create will be placed into this array
}
]
}

From here, you can reference this memo property as {{memo.path_to_here}}.

Error Handling

Cases arise where we need try/catch logic. This is accomplished with error handling methods. In the method we want to catch errors in, we use the handler key in the following way:

{
"brick": "json.parse",
"id": "jsonParseCatch",
"inputs": {
"string": "{{otherExec.output}}"
},
"handler": {
"method": // method name goes here,
"merge": "join"/"overwrite"/"throw",
"path": // only used in overwrite, must be a valid method output key
}
}

Fields:
* "method": Determines which method should process the error
* "merge": represents how the output of the error is handled
* If merge is set to "join": The output of the error handler is joined with the output of the method; only outputs that match the outputs of the method using the handler will be used, i.e. output for json.parse. This is the default behavior.
* If merge is set to "overwrite": The output of the error is written under the string specified by the path property onto the method's output. This key must be a valid output for the method, i.e. output for json.parse.
* If merge is set to "throw": The output of the error is thrown as an error, breaking execution up until another piece of handler logic catches it.

For the Metadata method being used as an error handler, an error key is used similarly to the variant key for metadata methods used as iterators. For example:

{
"name": "metadata_method",
"error": {
"_type": "object",
"_array": false,
"_defaultValue": {}
},
"zebricks": [
{
// modules you create will go here
}
]
}

Then to access properties of the error object, reference it with Mustache as {{error.path_to_here}}.

Passing Context

In some instances, you'll want to carry over context from an action or one metadata method into another metadata method, but not want to pass it into the inputs (i.e. a metadata method used for collections operations). To do this, you pass this data under the context group. To utilize the context group, you must add a key to your Event/Action method to define what kind of information to pass over. For example, if you had a previous method with the id "some_method", and you wanted access to all of the output of that method in a spawned metadata method used for collections, you'd need to write something like this:

{
"brick": "array.map",
"input": {
"collection": "{{prevData.array}}",
"concurrency": 4,
"context": {
"ref_to_use": {
"_type": "object",
"_array": false,
"_value": "{{some_method.output}}"
}
},
"flo": {
"_type": "flo",
"_value": "metadata_method"
}
}
}

Then, in order to reference "ref_to_use" in that metadata method, you would need to declare a context group for that metadata method, similar to the memo and variant keys. In the below example, you would need to add both a "context" group and "variant" key, because you are both passing in information ("context") and iterating through a collection ("variant").

{
"name": "metadata_method",
"variant": {
"_type": "object",
"_key": "item",
"_array": false
},
"context": {
"ref_to_use": {
"_type": "object",
"_array": false
}
},
"zebricks": [
{
// modules go here
}
]
}

Inside your modules for that method, you can then reference "ref_to_use" (or whatever you name your reference) as {{ref_to_use.path_to_here}} with Mustache.