Skip to content

Commit abf1196

Browse files
adatzercolmsnowplow
authored andcommitted
Add GTM SS preview header transformation (close #312)
1 parent fe488b4 commit abf1196

File tree

3 files changed

+558
-0
lines changed

3 files changed

+558
-0
lines changed

pkg/transform/gtmss_preview.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package transform
2+
3+
import (
4+
"errors"
5+
6+
"github.com/snowplow/snowbridge/config"
7+
"github.com/snowplow/snowbridge/pkg/models"
8+
9+
"github.com/snowplow/snowplow-golang-analytics-sdk/analytics"
10+
)
11+
12+
// The gtmssPreviewAdapter implements the Pluggable interface
13+
type gtmssPreviewAdapter func(i interface{}) (interface{}, error)
14+
15+
// ProvideDefault implements the ComponentConfigurable interface
16+
func (f gtmssPreviewAdapter) ProvideDefault() (interface{}, error) {
17+
return nil, nil
18+
}
19+
20+
// Create implements the ComponentCreator interface.
21+
func (f gtmssPreviewAdapter) Create(i interface{}) (interface{}, error) {
22+
return f(i)
23+
}
24+
25+
// gtmssPreviewAdapterGenerator returns a gtmssPreviewAdapter
26+
func gtmssPreviewAdapterGenerator(f func() (TransformationFunction, error)) gtmssPreviewAdapter {
27+
return func(i interface{}) (interface{}, error) {
28+
if i != nil {
29+
return nil, errors.New("unexpected configuration input for gtmssPreview transformation")
30+
}
31+
32+
return f()
33+
}
34+
}
35+
36+
// gtmssPreviewConfigFunction returns a transformation function
37+
func gtmssPreviewConfigFunction() (TransformationFunction, error) {
38+
ctx := "contexts_com_google_tag-manager_server-side_preview_mode_1"
39+
property := "x-gtm-server-preview"
40+
header := "x-gtm-server-preview"
41+
return gtmssPreviewTransformation(ctx, property, header), nil
42+
}
43+
44+
// GTMSSPreviewConfigPair is the configuration pair for the gtmss preview transformation
45+
var GTMSSPreviewConfigPair = config.ConfigurationPair{
46+
Name: "gtmssPreview",
47+
Handle: gtmssPreviewAdapterGenerator(gtmssPreviewConfigFunction),
48+
}
49+
50+
// gtmssPreviewTransformation returns a transformation function
51+
func gtmssPreviewTransformation(ctx, property, headerKey string) TransformationFunction {
52+
return func(message *models.Message, interState interface{}) (*models.Message, *models.Message, *models.Message, interface{}) {
53+
parsedEvent, err := IntermediateAsSpEnrichedParsed(interState, message)
54+
if err != nil {
55+
message.SetError(err)
56+
return nil, nil, message, nil
57+
}
58+
59+
headerVal, err := extractHeaderValue(parsedEvent, ctx, property)
60+
if err != nil {
61+
message.SetError(err)
62+
return nil, nil, message, nil
63+
}
64+
if headerVal != nil {
65+
if message.HTTPHeaders == nil {
66+
message.HTTPHeaders = make(map[string]string)
67+
}
68+
message.HTTPHeaders[headerKey] = *headerVal
69+
return message, nil, nil, parsedEvent
70+
}
71+
72+
return message, nil, nil, parsedEvent
73+
}
74+
}
75+
76+
func extractHeaderValue(parsedEvent analytics.ParsedEvent, ctx, prop string) (*string, error) {
77+
values, err := parsedEvent.GetContextValue(ctx, prop)
78+
if err != nil {
79+
return nil, err
80+
}
81+
82+
headerVals, ok := values.([]interface{})
83+
if !ok {
84+
// this is generally not expected to happen
85+
return nil, errors.New("invalid return type encountered")
86+
}
87+
88+
if len(headerVals) > 0 {
89+
// use only first value found
90+
headerVal, ok := headerVals[0].(string)
91+
if !ok {
92+
return nil, errors.New("invalid header value")
93+
}
94+
95+
return &headerVal, nil
96+
}
97+
98+
// no value found
99+
return nil, nil
100+
}

0 commit comments

Comments
 (0)