forked from customerio/go-customerio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
customerio.go
132 lines (104 loc) · 3.18 KB
/
customerio.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package customerio
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"path"
"strconv"
)
// CustomerIO wraps the customer.io API, see: http://customer.io/docs/api/rest.html
type CustomerIO struct {
siteID string
apiKey string
Host string
SSL bool
}
// CustomerIOError is returned by any method that fails at the API level
type CustomerIOError struct {
status int
url string
body []byte
}
func (e *CustomerIOError) Error() string {
return fmt.Sprintf("%v: %v %v", e.status, e.url, string(e.body))
}
// NewCustomerIO creates a new CustomerIO object to perform requests on the supplied credentials
func NewCustomerIO(siteID, apiKey string) *CustomerIO {
return &CustomerIO{siteID, apiKey, "track.customer.io", true}
}
// Identify identifies a customer and sets their attributes
func (c *CustomerIO) Identify(customerID string, attributes map[string]interface{}) error {
j, err := json.Marshal(attributes)
if err != nil {
return err
}
status, responseBody, err := c.request("PUT", c.customerURL(customerID), j)
if err != nil {
return err
} else if status != 200 {
return &CustomerIOError{status, c.customerURL(customerID), responseBody}
}
return nil
}
// Track sends a single event to Customer.io for the supplied user
func (c *CustomerIO) Track(customerID string, eventName string, data map[string]interface{}) error {
body := map[string]interface{}{"name": eventName, "data": data}
j, err := json.Marshal(body)
if err != nil {
return err
}
status, responseBody, err := c.request("POST", c.eventURL(customerID), j)
if err != nil {
return err
} else if status != 200 {
return &CustomerIOError{status, c.eventURL(customerID), responseBody}
}
return nil
}
// Delete deletes a customer
func (c *CustomerIO) Delete(customerID string) error {
status, responseBody, err := c.request("DELETE", c.customerURL(customerID), []byte{})
if err != nil {
return err
} else if status != 200 {
return &CustomerIOError{status, c.customerURL(customerID), responseBody}
}
return nil
}
func (c *CustomerIO) auth() string {
return base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("%v:%v", c.siteID, c.apiKey)))
}
func (c *CustomerIO) protocol() string {
if !c.SSL {
return "http://"
}
return "https://"
}
func (c *CustomerIO) customerURL(customerID string) string {
return c.protocol() + path.Join(c.Host, "api/v1", "customers", customerID)
}
func (c *CustomerIO) eventURL(customerID string) string {
return c.protocol() + path.Join(c.Host, "api/v1", "customers", customerID, "events")
}
func (c *CustomerIO) request(method, url string, body []byte) (status int, responseBody []byte, err error) {
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return 0, nil, err
}
req.Header.Add("Authorization", fmt.Sprintf("Basic %v", c.auth()))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Content-Length", strconv.Itoa(len(body)))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return 0, nil, err
}
defer resp.Body.Close()
status = resp.StatusCode
if resp.ContentLength >= 0 {
responseBody = make([]byte, resp.ContentLength)
resp.Body.Read(responseBody)
}
return status, responseBody, nil
}