Writing a script
Custom transformation scripts may be defined in Javascript and provided to Snowbridge.
The scripting interface
The script must define a main function with a single argument. Snowbridge will pass the engineProtocol
data structure as the argument:
type engineProtocol struct {
FilterOut bool
PartitionKey string
Data interface{}
HTTPHeaders map[string]string
}
This structure is represented as an object in the script engine, and serves as both the input and output of the script.
Scripts must define a main
function with a single input argument (JSDoc for type information is optional):
/**
* @typedef {object} EngineProtocol
* @property {boolean} FilterOut
* @property {string} PartitionKey
* @property {(string | Object.<string, ?>)} Data
* @property {Object.<string, string>} HTTPHeaders
*/
/**
* @param {EngineProtocol} input
* @return {Partial<EngineProtocol>}
*/
function main(input) {
return input
}
Accessing data
Scripts can access the message Data at input.Data
, and can return modified data by returning it in the Data
field of the output. Likewise for the partition key to be used for the destination - input.PartitionKey
and the PartitionKey
field of the output.
By default, the input's Data
field will be a string in enriched TSV format.
This can be changed with the SpEnrichedToJson transform, or the Javascript transformation itself has a snowplow_mode
option, which transforms the data to an object first.
The output of the script must be an object which maps to engineProtocol.
snowplow_mode
snowplow_mode
uses the Go Analytics SDK to parse the TSV fields into an object suitable for working with in Go.
The result of the ParsedEvent.ToMap()
method is the input to your transform function.
The keys of the resulting map are defined by the Analytics SDK.
Values are primitives (string, number, boolean) or, for timestamps (e.g. derived_tstamp
, collector_tstamp
), time.Time
objects.
To work with native Javascript Date objects for timestamps, construct one via new Date(ts.UnixMilli())
where ts
is a time.Time
instance.
When returned as part of Data
, time.Time
instances will serialize in JSON as RFC3339 strings.
Structured data (Self Describing Event payloads and Entities) will have keys with a prefix of unstruct_event_
or contexts_
, the vendor name converted to snake case, the event/entity name in snake case, and the schema model version. For example:
Schema URI | Type | Key |
---|---|---|
iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0 | Entity | contexts_com_snowplowanalytics_snowplow_web_page_1 |
iglu:org.w3/PerformanceNavigationTiming/jsonschema/1-0-0 | Entity | contexts_org_w3_performance_navigation_timing_1 |
iglu:com.urbanairship.connect/OPEN/jsonschema/1-0-0 | Event | unstruct_event_com_urbanairship_connect_open_1 |
Timestamps in structured data values will always have their primitive representation (string/number) and not be time.Time
instances.
Transforming Data
For all the below examples, the input is a string representation of the below JSON object. For Snowplow data, using snowplow_mode
will produce a JSON object input - see the snowplow example.
{
"name": "Bruce",
"id": "b47m4n",
"batmobileCount": 1
}
To modify the message data, return an object which conforms to EngineProtocol, with the Data
field set to the modified data. The Data
field may be returned as either a string, or an object.
loading...
Filtering
If the FilterOut
field of the output is returned as true
, the message will be acknowledged immediately and won't be sent to the target. This will be the behavior regardless of what is returned to the other fields in the protocol.
loading...
Setting the Partition Key
To set the Partition Key in the message, you can simply set the input's PartitionKey field, and return it:
loading...
Or, if modifying the data as well, return the modified data and PartitionKey field:
loading...
Setting an HTTP header
For the http
target only, you can specify a set of HTTP headers, which will be appended to the configured headers for the http
target. Do so by providing an object in the HTTPHeaders
field:
loading...
The headers will only be included if the target has the dynamic_headers = true
setting configured.
Configuration
Once your script is ready, you can configure it in the app by following the Javascript configuration page.
You can also find some complete example use cases in the examples section.