Skip to content

Commit abe01c5

Browse files
adding SDK guides for readme.io (#261)
* adding SDK guides for readme.io * Changes for github support. Co-authored-by: Yasir Ali <[email protected]>
1 parent 35eb16d commit abe01c5

21 files changed

+1308
-0
lines changed

docs/010 - install-sdk-go.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: "Install SDK"
3+
excerpt: ""
4+
slug: "install-sdk-go"
5+
hidden: false
6+
createdAt: "2019-08-21T21:13:10.351Z"
7+
updatedAt: "2019-09-05T15:25:17.864Z"
8+
---
9+
The Go SDK is open source and available on [GitHub](https://github.com/optimizely/go-sdk).
10+
11+
You can install using the following command:
12+
13+
```go
14+
go get github.com/optimizely/go-sdk
15+
```
16+
17+
### Install from CLI source
18+
19+
```go
20+
go get github.com/optimizely/go-sdk
21+
$GOPATH/src/github.com/optimizely/go-sdk
22+
go install
23+
```

docs/020 - initialize-sdk-go.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: "Initialize SDK"
3+
excerpt: ""
4+
slug: "initialize-sdk-go"
5+
hidden: false
6+
createdAt: "2019-08-21T21:13:33.317Z"
7+
updatedAt: "2019-08-21T21:13:45.319Z"
8+
---
9+
To initialize the **OptimizelyClient** you will need either the SDK key or hard-coded JSON datafile.
10+
```go
11+
import "github.com/optimizely/go-sdk/pkg/client"
12+
13+
optimizelyFactory := &client.OptimizelyFactory{
14+
SDKKey: "[SDK_KEY_HERE]",
15+
Datafile: []byte("DATAFILE_JSON_STRING_HERE")
16+
}
17+
18+
// Instantiate a static client (no datafile polling)
19+
optlyClient, err := optimizelyFactory.StaticClient()
20+
21+
// Instantiates a client that syncs the datafile in the background
22+
optlyClient, err := optimizelyFactory.Client()
23+
```

docs/030 - example-usage-go.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: "Example usage"
3+
excerpt: ""
4+
slug: "example-usage-go"
5+
hidden: true
6+
createdAt: "2019-09-11T22:26:55.008Z"
7+
updatedAt: "2019-12-13T01:40:10.425Z"
8+
---
9+
Once you've installed the Go SDK, import the Optimizely library into your code, get your Optimizely project's datafile, and instantiate a client. Then, you can use the client to evaluate feature flags, activate an A/B test, or feature test.
10+
11+
This example demonstrates the basic usage of each of these concepts. Each concept is described in detail in this guide, and you can find each method's arguments and return values in the [API Reference](doc:activate).
12+
13+
This example shows how to:
14+
1. Evaluate a feature with the key `price_filter` and check a configuration variable on it called `min_price`. The SDK evaluates your feature test and rollouts to determine whether the feature is enabled for a particular user, and which minimum price they should see if so.
15+
16+
2. Run an A/B test called `app_redesign`. This experiment has two variations, `control` and `treatment`. It uses the `activate` method to assign the user to a variation, returning its key. As a side effect, the activate function also sends an impression event to Optimizely to record that the current user has been exposed to the experiment.
17+
18+
3. Use event tracking to track an event called `purchased`. This conversion event measures the impact of an experiment. Using the track method, the purchase is automatically attributed back to the running A/B and feature tests we've activated, and the SDK sends a network request to Optimizely via the customizable event dispatcher so we can count it in your results page.
19+
20+
```go
21+
import (
22+
optly "github.com/optimizely/go-sdk"
23+
)
24+
25+
attributes := map[string]interface{}{
26+
"DEVICE": "iPhone",
27+
"hey": 2,
28+
}
29+
30+
user := optly.UserContext("userId", attributes)
31+
32+
// Instantiate an Optimizely client
33+
if client, err := optly.Client("SDK_KEY_HERE"); err == nil {
34+
client.IsFeatureEnabled("price_filter", user)
35+
minPrice, _ := client.GetFeatureVariableInteger("price_filter", "min_price", user)
36+
37+
// Activate an A/B test
38+
variation, _ := client.Activate("app_redesign", user)
39+
if variation == "control" {
40+
// Execute code for variation A
41+
} else if variation == "treatment" {
42+
// Execute code for variation B
43+
} else {
44+
// Execute code for users who don't qualify for the experiment
45+
}
46+
client.Track("purchased", user, map[string]interface{}{})
47+
}
48+
```

docs/040 - optimizelyconfig-go.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
---
2+
title: "OptimizelyConfig"
3+
excerpt: ""
4+
slug: "optimizelyconfig-go"
5+
hidden: true
6+
createdAt: "2020-01-17T19:10:55.970Z"
7+
updatedAt: "2020-01-28T21:53:26.607Z"
8+
---
9+
### Overview
10+
11+
Full Stack SDKs open a well-defined set of public APIs, hiding all implementation details. However, some clients may need access to project configuration data within the "datafile".
12+
13+
In this document, we extend our public APIs to define data models and access methods, which clients can use to access project configuration data.
14+
15+
### OptimizelyConfig API
16+
17+
A public configuration data model (OptimizelyConfig) is defined below as a structured format of static Optimizely Project data.
18+
19+
OptimizelyConfig can be accessed from OptimizelyClient (top-level) with this public API call:
20+
```go
21+
client, e := optimizelyFactory.Client()
22+
var config = client.GetOptimizelyConfig()
23+
```
24+
`GetOptimizelyConfig` returns an `config.OptimizelyConfig` instance which include a datafile revision number, all experiments, and feature flags mapped by their key values.
25+
26+
>ℹ️ Note
27+
>
28+
> When the SDK datafile is updated (the client can add a notification listener for `ProjectConfigUpdateNotification` to get notified), the client is expected to call the method to get the updated OptimizelyConfig data. See examples below.
29+
30+
```go
31+
// OptimizelyConfig is an object describing the current project configuration data
32+
type OptimizelyConfig struct {
33+
Revision string
34+
ExperimentsMap map[string]OptimizelyExperiment
35+
FeaturesMap map[string]OptimizelyFeature
36+
}
37+
38+
39+
// OptimizelyFeature is an object describing a feature
40+
type OptimizelyFeature struct {
41+
ID string
42+
Key string
43+
ExperimentsMap map[string]OptimizelyExperiment
44+
VariablesMap map[string]OptimizelyVariable
45+
}
46+
47+
48+
// OptimizelyExperiment is an object describing a feature test or an A/B test
49+
type OptimizelyExperiment struct {
50+
ID string
51+
Key string
52+
VariationsMap map[string]OptimizelyVariation
53+
}
54+
55+
56+
// OptimizelyVariation is an object describing a variation in a feature test or A/B //test
57+
type OptimizelyVariation struct {
58+
ID string
59+
Key string
60+
FeatureEnabled bool
61+
VariablesMap map[string]OptimizelyVariable
62+
}
63+
64+
65+
// OptimizelyVariable is an object describing a feature variable
66+
type OptimizelyVariable struct {
67+
ID string
68+
Key string
69+
Type string
70+
Value string
71+
}
72+
```
73+
74+
### Examples
75+
OptimizelyConfig can be accessed from OptimizelyClient (top-level) like this:
76+
77+
```go
78+
client, e := optimizelyFactory.Client()
79+
// all experiments
80+
var experimentsMap = optimizelyConfig.ExperimentsMap
81+
var experiments = []config.OptimizelyExperiment{}
82+
var experimentKeys = []string{}
83+
84+
for experimentKey, experiment := range experimentsMap {
85+
experimentKeys = append(experimentKeys, experimentKey)
86+
experiments = append(experiments, experiment)
87+
}
88+
89+
for _, experimentKey := range experimentKeys {
90+
var experiment = experimentsMap[experimentKey]
91+
92+
// all variations for an experiment
93+
var variationsMap = experiment.VariationsMap
94+
var variations = []config.OptimizelyVariation{}
95+
var variationKeys = []string{}
96+
97+
for variationKey, variation := range variationsMap {
98+
variations = append(variations, variation)
99+
variationKeys = append(variationKeys, variationKey)
100+
}
101+
102+
for _, variationKey := range variationKeys {
103+
var variation = variationsMap[variationKey]
104+
105+
// all variables for a variation
106+
var variablesMap = variation.VariablesMap
107+
var variables = []config.OptimizelyVariable{}
108+
var variableKeys = []string{}
109+
110+
for variableKey, variable := range variablesMap {
111+
variables = append(variables, variable)
112+
variableKeys = append(variableKeys, variableKey)
113+
}
114+
115+
for _, variableKey := range variableKeys {
116+
var variable = variablesMap[variableKey]
117+
// use variable data here...
118+
}
119+
}
120+
}
121+
122+
// all features
123+
var featuresMap = optimizelyConfig.FeaturesMap
124+
var features = []config.OptimizelyFeature{}
125+
var featureKeys = []string{}
126+
127+
for featureKey, feature := range featuresMap {
128+
features = append(features, feature)
129+
featureKeys = append(featureKeys, featureKey)
130+
}
131+
132+
for _, featureKey := range featureKeys {
133+
var feature = featuresMap[featureKey]
134+
135+
// all experiments for a feature
136+
var experimentsMap = feature.ExperimentsMap
137+
var experiments = []config.OptimizelyExperiment{}
138+
var experimentKeys = []string{}
139+
140+
for experimentKey, experiment := range experimentsMap {
141+
experiments = append(experiments, experiment)
142+
experimentKeys = append(experimentKeys, experimentKey)
143+
}
144+
145+
// use experiments and other feature data here...
146+
}
147+
148+
// listen to ProjectConfigUpdateNotification to get updated data
149+
callback := func(notification notification.ProjectConfigUpdateNotification) {
150+
var newConfig = client.GetOptimizelyConfig()
151+
// ...
152+
}
153+
client.ConfigManager.OnProjectConfigUpdate(callback)
154+
```
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
title: "Implement a user profile service"
3+
excerpt: ""
4+
slug: "implement-a-user-profile-service-go"
5+
hidden: true
6+
createdAt: "2019-09-12T13:56:27.183Z"
7+
updatedAt: "2019-12-03T20:10:31.031Z"
8+
---
9+
Use a **User Profile Service** to persist information about your users and ensure variation assignments are sticky. The User Profile Service implementation you provide will override Optimizely's default bucketing behavior in cases when an experiment assignment has been saved.
10+
11+
When implementing in a multi-server or stateless environment, we suggest using this interface with a backend like Cassandra or Redis. You can decide how long you want to keep your sticky bucketing around by configuring these services.
12+
13+
Implementing a User Profile Service is optional and is only necessary if you want to keep variation assignments sticky even when experiment conditions are changed while it is running (for example, audiences, attributes, variation pausing, and traffic distribution). Otherwise, the Go SDK is stateless and relies on deterministic bucketing to return consistent assignments. See [How bucketing works](doc:how-bucketing-works) for more information.
14+
### Implement a user profile service
15+
Refer to the code samples below to provide your own User Profile Service. It should expose two functions with the following signatures:
16+
17+
* lookup: Takes a user ID string and returns a user profile matching the schema below.
18+
* save: Takes a user profile and persists it.
19+
20+
```go
21+
import ( "github.com/optimizely/go-sdk/pkg/decision" )
22+
23+
// CustomUserProfileService is custom implementation of the UserProfileService interface
24+
type CustomUserProfileService struct {
25+
}
26+
27+
// Lookup is used to retrieve past bucketing decisions for users
28+
func (s *CustomUserProfileService) Lookup(userID string) decision.UserProfile {
29+
return decision.UserProfile{}
30+
}
31+
32+
// Save is used to save bucketing decisions for users
33+
func (s *CustomUserProfileService) Save(userProfile decision.UserProfile) {
34+
}
35+
36+
```
37+
**The UserProfile struct**
38+
```go
39+
type UserProfile struct {
40+
ID string
41+
ExperimentBucketMap map[UserDecisionKey]string
42+
}
43+
44+
// UserDecisionKey is used to access the saved decisions in a user profile
45+
type UserDecisionKey struct {
46+
ExperimentID string
47+
Field string
48+
}
49+
50+
// Sample user profile with a saved variation
51+
userProfile := decision.UserProfile{
52+
ID: "optly_user_1",
53+
ExperimentBucketMap: map[decision.UserDecisionKey]string{
54+
decision.UserDecisionKey{ExperimentID: "experiment_1", Field: "variation_id"
55+
}: "variation_1234",
56+
},
57+
}
58+
```
59+
60+
Use `experiment_bucket_map` from the `UserProfile` struct to override the default bucketing behavior and define an alternate experiment variation for a given user. For each experiment that you want to override, add an object to the map. Use the experiment ID as the key and include a variation_id property that specifies the desired variation. If there isn't an entry for an experiment, then the default bucketing behavior persists.
61+
62+
The Go SDK uses the field `variation_id` by default to create a decision key. Create a decision key manually with the method `decision.NewUserDecisionKey`:
63+
64+
```go
65+
decisionKey := decision.NewUserDecisionKey("experiment_id")
66+
```
67+
**Passing a User Profile Service Implementation to the OptimizelyClient:**
68+
```go
69+
userProfileService := new(CustomUserProfileService)
70+
optimizelyClient, err := factory.Client(
71+
client.WithUserProfileService(userProfileService),
72+
)
73+
74+
```
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
title: "Configure event dispatcher"
3+
excerpt: ""
4+
slug: "configure-event-dispatcher-go"
5+
hidden: true
6+
createdAt: "2019-09-12T13:58:15.596Z"
7+
updatedAt: "2019-12-10T00:19:39.940Z"
8+
---
9+
The Optimizely SDKs make HTTP requests for every impression or conversion that gets triggered. Each SDK has a built-in **event dispatcher** for handling these events, but we recommend overriding it based on the specifics of your environment.
10+
11+
The Go SDK has an out-of-the-box asynchronous dispatcher. We recommend customizing the event dispatcher you use in production to ensure that you queue and send events in a manner that scales to the volumes handled by your application. Customizing the event dispatcher allows you to take advantage of features like batching, which makes it easier to handle large event volumes efficiently or to implement retry logic when a request fails. You can build your dispatcher from scratch or start with the provided dispatcher.
12+
13+
The examples show that to customize the event dispatcher, initialize the Optimizely client (or manager) with an event dispatcher instance.
14+
```go
15+
import "github.com/optimizely/go-sdk/pkg/event"
16+
17+
type CustomEventDispatcher struct {
18+
}
19+
20+
// DispatchEvent dispatches event with callback
21+
func (d *CustomEventDispatcher) DispatchEvent(event event.LogEvent) (bool, error) {
22+
dispatchedEvent := map[string]interface{}{
23+
"url": event.EndPoint,
24+
"http_verb": "POST",
25+
"headers": map[string]string{"Content-Type": "application/json"},
26+
"params": event.Event,
27+
}
28+
return true, nil
29+
}
30+
31+
```
32+
33+
```go
34+
import (
35+
"github.com/optimizely/go-sdk/pkg/client"
36+
"github.com/optimizely/go-sdk/pkg/event"
37+
)
38+
39+
optimizelyFactory := &client.OptimizelyFactory{
40+
SDKKey: "SDK_KEY_HERE",
41+
}
42+
43+
customEventDispatcher := &CustomEventDispatcher{}
44+
45+
// Create an Optimizely client with the custom event dispatcher
46+
optlyClient, e := optimizelyFactory.Client(client.WithEventDispatcher(customEventDispatcher))
47+
48+
49+
```
50+
51+
The event dispatcher should implement a `DispatchEvent` function, which takes in one argument: `event.LogEvent`. In this function, you should send a `POST` request to the given `event.EndPoint` using the `event.EndPoint` as the body of the request (be sure to stringify it to JSON) and `{content-type: 'application/json'}` in the headers.
52+
53+
>⚠️ Important
54+
>
55+
> If you are using a custom event dispatcher, do not modify the event payload returned from Optimizely. Modifying this payload will alter your results.
56+
57+
By default, our Go SDK uses a [basic asynchronous event dispatcher](https://github.com/optimizely/go-sdk/blob/master/pkg/event/dispatcher.go).

0 commit comments

Comments
 (0)