promoted-ruby-client 0.1.0 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/Gemfile +12 -1
- data/Gemfile.lock +83 -5
- data/README.md +214 -138
- data/bin/setup +1 -1
- data/dev.md +9 -0
- data/lib/promoted/ruby/client.rb +272 -50
- data/lib/promoted/ruby/client/constants.rb +37 -0
- data/lib/promoted/ruby/client/errors.rb +8 -21
- data/lib/promoted/ruby/client/extensions.rb +41 -0
- data/lib/promoted/ruby/client/faraday_http_client.rb +36 -0
- data/lib/promoted/ruby/client/request_builder.rb +147 -0
- data/lib/promoted/ruby/client/sampler.rb +13 -0
- data/lib/promoted/ruby/client/util.rb +17 -0
- data/lib/promoted/ruby/client/validator.rb +159 -0
- data/lib/promoted/ruby/client/version.rb +1 -1
- data/promoted-ruby-client.gemspec +2 -2
- metadata +12 -6
- data/lib/promoted/ruby/client/options.rb +0 -206
- data/lib/promoted/ruby/client/settings.rb +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6638e3f3f180e08d693f00d9d53caae30cfc737b2023adf0d181c18c1e379369
|
|
4
|
+
data.tar.gz: 429c6c2cfc5022ea9f38913cbc0e4b7d218787f817152661f2624d8265fd1f8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9e9e040d1c232767af0004c92c7b3a79277b7ac0e5a3c45509c46bf869a6a51ed7b5ad4273c68c03c86833482607a2b63da8c43f819f73e069ca6a3caf24ddd3
|
|
7
|
+
data.tar.gz: 973bbfd858e00e5f81a42f221c5d2a90c8c2fb3bec93e5b1d8f38ca58c42c47382aa4ed777852ec3bee51483ff211b5da9041a075e285b738107be5f8c08567d
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
|
@@ -6,4 +6,15 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
8
|
gem 'faraday', '~> 1.4.1'
|
|
9
|
-
gem '
|
|
9
|
+
gem 'faraday_middleware'
|
|
10
|
+
gem 'faraday-net_http'
|
|
11
|
+
gem 'concurrent-ruby', require: 'concurrent'
|
|
12
|
+
|
|
13
|
+
group :development do
|
|
14
|
+
gem 'ruby-debug-ide', group: :development
|
|
15
|
+
gem 'debase', '>= 0.2.5.beta2', group: :development
|
|
16
|
+
gem 'jaro_winkler', group: :development
|
|
17
|
+
gem 'solargraph', group: :development
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
gem 'simplecov', require: false, group: :test
|
data/Gemfile.lock
CHANGED
|
@@ -1,24 +1,56 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
promoted-ruby-client (0.1.
|
|
4
|
+
promoted-ruby-client (0.1.5)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
|
|
9
|
+
ast (2.4.2)
|
|
10
|
+
backport (1.2.0)
|
|
11
|
+
benchmark (0.1.1)
|
|
12
|
+
concurrent-ruby (1.1.9)
|
|
13
|
+
debase (0.2.5.beta2)
|
|
14
|
+
debase-ruby_core_source (>= 0.10.12)
|
|
15
|
+
debase-ruby_core_source (0.10.12)
|
|
10
16
|
diff-lcs (1.4.4)
|
|
11
|
-
|
|
17
|
+
docile (1.4.0)
|
|
18
|
+
e2mmap (0.1.0)
|
|
19
|
+
faraday (1.4.3)
|
|
20
|
+
faraday-em_http (~> 1.0)
|
|
21
|
+
faraday-em_synchrony (~> 1.0)
|
|
12
22
|
faraday-excon (~> 1.1)
|
|
13
23
|
faraday-net_http (~> 1.0)
|
|
14
24
|
faraday-net_http_persistent (~> 1.1)
|
|
15
25
|
multipart-post (>= 1.2, < 3)
|
|
16
26
|
ruby2_keywords (>= 0.0.4)
|
|
27
|
+
faraday-em_http (1.0.0)
|
|
28
|
+
faraday-em_synchrony (1.0.0)
|
|
17
29
|
faraday-excon (1.1.0)
|
|
18
30
|
faraday-net_http (1.0.1)
|
|
19
31
|
faraday-net_http_persistent (1.1.0)
|
|
32
|
+
faraday_middleware (1.0.0)
|
|
33
|
+
faraday (~> 1.0)
|
|
34
|
+
jaro_winkler (1.5.4)
|
|
35
|
+
kramdown (2.3.1)
|
|
36
|
+
rexml
|
|
37
|
+
kramdown-parser-gfm (1.1.0)
|
|
38
|
+
kramdown (~> 2.0)
|
|
39
|
+
mini_portile2 (2.5.3)
|
|
20
40
|
multipart-post (2.1.1)
|
|
41
|
+
nokogiri (1.11.7)
|
|
42
|
+
mini_portile2 (~> 2.5.0)
|
|
43
|
+
racc (~> 1.4)
|
|
44
|
+
parallel (1.20.1)
|
|
45
|
+
parser (3.0.1.1)
|
|
46
|
+
ast (~> 2.4.1)
|
|
47
|
+
racc (1.5.2)
|
|
48
|
+
rainbow (3.0.0)
|
|
21
49
|
rake (10.5.0)
|
|
50
|
+
regexp_parser (2.1.1)
|
|
51
|
+
reverse_markdown (2.0.0)
|
|
52
|
+
nokogiri
|
|
53
|
+
rexml (3.2.5)
|
|
22
54
|
rspec (3.10.0)
|
|
23
55
|
rspec-core (~> 3.10.0)
|
|
24
56
|
rspec-expectations (~> 3.10.0)
|
|
@@ -32,18 +64,64 @@ GEM
|
|
|
32
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
33
65
|
rspec-support (~> 3.10.0)
|
|
34
66
|
rspec-support (3.10.2)
|
|
67
|
+
rubocop (1.17.0)
|
|
68
|
+
parallel (~> 1.10)
|
|
69
|
+
parser (>= 3.0.0.0)
|
|
70
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
71
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
72
|
+
rexml
|
|
73
|
+
rubocop-ast (>= 1.7.0, < 2.0)
|
|
74
|
+
ruby-progressbar (~> 1.7)
|
|
75
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
76
|
+
rubocop-ast (1.7.0)
|
|
77
|
+
parser (>= 3.0.1.1)
|
|
78
|
+
ruby-debug-ide (0.7.2)
|
|
79
|
+
rake (>= 0.8.1)
|
|
80
|
+
ruby-progressbar (1.11.0)
|
|
35
81
|
ruby2_keywords (0.0.4)
|
|
82
|
+
simplecov (0.21.2)
|
|
83
|
+
docile (~> 1.1)
|
|
84
|
+
simplecov-html (~> 0.11)
|
|
85
|
+
simplecov_json_formatter (~> 0.1)
|
|
86
|
+
simplecov-html (0.12.3)
|
|
87
|
+
simplecov_json_formatter (0.1.3)
|
|
88
|
+
solargraph (0.42.3)
|
|
89
|
+
backport (~> 1.2)
|
|
90
|
+
benchmark
|
|
91
|
+
bundler (>= 1.17.2)
|
|
92
|
+
diff-lcs (~> 1.4)
|
|
93
|
+
e2mmap
|
|
94
|
+
jaro_winkler (~> 1.5)
|
|
95
|
+
kramdown (~> 2.3)
|
|
96
|
+
kramdown-parser-gfm (~> 1.1)
|
|
97
|
+
parser (~> 3.0)
|
|
98
|
+
reverse_markdown (>= 1.0.5, < 3)
|
|
99
|
+
rubocop (>= 0.52)
|
|
100
|
+
thor (~> 1.0)
|
|
101
|
+
tilt (~> 2.0)
|
|
102
|
+
yard (~> 0.9, >= 0.9.24)
|
|
103
|
+
thor (1.1.0)
|
|
104
|
+
tilt (2.0.10)
|
|
105
|
+
unicode-display_width (2.0.0)
|
|
106
|
+
yard (0.9.26)
|
|
36
107
|
|
|
37
108
|
PLATFORMS
|
|
38
109
|
ruby
|
|
39
110
|
|
|
40
111
|
DEPENDENCIES
|
|
41
112
|
bundler (~> 1.17)
|
|
42
|
-
|
|
113
|
+
concurrent-ruby
|
|
114
|
+
debase (>= 0.2.5.beta2)
|
|
43
115
|
faraday (~> 1.4.1)
|
|
116
|
+
faraday-net_http
|
|
117
|
+
faraday_middleware
|
|
118
|
+
jaro_winkler
|
|
44
119
|
promoted-ruby-client!
|
|
45
120
|
rake (~> 10.0)
|
|
46
121
|
rspec (~> 3.0)
|
|
122
|
+
ruby-debug-ide
|
|
123
|
+
simplecov
|
|
124
|
+
solargraph
|
|
47
125
|
|
|
48
126
|
BUNDLED WITH
|
|
49
|
-
1.17.
|
|
127
|
+
1.17.3
|
data/README.md
CHANGED
|
@@ -2,45 +2,166 @@
|
|
|
2
2
|
|
|
3
3
|
Ruby client designed for calling Promoted's Delivery and Metrics API.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
More information at [http://www.promoted.ai](http://www.promoted.ai)
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Installation
|
|
8
|
+
```gem 'promoted-ruby-client'```
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
## Local Development
|
|
11
|
+
1. Clone or fork the repo on your local machine
|
|
12
|
+
2. `cd promoted-ruby-client`
|
|
13
|
+
3. `bundle`
|
|
14
|
+
4. To test interactively: `irb -Ilib -rpromoted/ruby/client`
|
|
10
15
|
|
|
16
|
+
## Dependencies
|
|
17
|
+
|
|
18
|
+
### [Faraday](https://github.com/lostisland/faraday)
|
|
19
|
+
HTTP client for calling Promoted.
|
|
20
|
+
### [Concurrent Ruby](https://github.com/ruby-concurrency/concurrent-ruby)
|
|
21
|
+
Provides a thread pool for making shadow traffic requests to Delivery API in the background on a subset of calls to ```prepare_for_logging```
|
|
22
|
+
## Creating a Client
|
|
23
|
+
```rb
|
|
24
|
+
client = Promoted::Ruby::Client::PromotedClient.new
|
|
11
25
|
```
|
|
12
|
-
def get_items args
|
|
13
|
-
items = retrieve_items((args))
|
|
14
|
-
async_log_request(items)
|
|
15
|
-
return items
|
|
16
|
-
end
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
This client will suffice for building log requests. To send actually send traffing to the API, some configuration is required.
|
|
28
|
+
|
|
29
|
+
```rb
|
|
30
|
+
client = Promoted::Ruby::Client::PromotedClient.new({
|
|
31
|
+
:metrics_endpoint = "https://<get this from Promoted>",
|
|
32
|
+
:delivery_endpoint = "https://<get this from Promoted>",
|
|
33
|
+
:metrics_api_key = "<get this from Promoted>",
|
|
34
|
+
:delivery_api_key = "<get this from Promoted>"
|
|
35
|
+
})
|
|
24
36
|
```
|
|
25
37
|
|
|
26
|
-
|
|
38
|
+
### Client Configuration Parameters
|
|
39
|
+
Name | Type | Description
|
|
40
|
+
---- | ---- | -----------
|
|
41
|
+
```:delivery_endpoint``` | String | POST URL for the Promoted Delivery API (get this from Promoted)
|
|
42
|
+
```:metrics_endpoint``` | String | POST URL for the Promoted Metrics API (get this from Promoted)
|
|
43
|
+
```:metrics_api_key``` | String | Used as the ```x-api-key``` header on Metrics API requests to Promoted (get this value from Promoted)
|
|
44
|
+
```:delivery_api_key``` | String | Used as the ```x-api-key``` header on Delivery API requests to Promoted (get this value from Promoted)
|
|
45
|
+
```:delivery_timeout_millis``` | Number | Timeout on the Delivery API call. Defaults to 3000.
|
|
46
|
+
```:metrics_timeout_millis``` | Number | Timeout on the Metrics API call. Defaults to 3000.
|
|
47
|
+
```:perform_checks``` | Boolean | Whether or not to perform detailed input validation, defaults to true but may be disabled for performance
|
|
48
|
+
```:logger``` | Ruby Logger-compatible logger | Defaults to nil (no logging). Example: ```Logger.new(STDERR, :progname => 'promotedai')```
|
|
49
|
+
```:shadow_traffic_delivery_percent``` | Number between 0 and 1 | % of ```prepare_for_logging``` traffic that gets directed to Delivery API as "shadow traffic". Defaults to 0 (no shadow traffic).
|
|
50
|
+
```:default_request_headers``` | Hash | Additional headers to send on the request beyond ```x-api-key```. Defaults to {}
|
|
51
|
+
```:default_only_log``` | Boolean | If true, the ```deliver``` method will not direct traffic to Delivery API but rather return a request suitable for logging. Defaults to false.
|
|
52
|
+
```:should_apply_treatment_func``` | Proc | Called during delivery, accepts an experiment and returns a Boolean indicating whether the request should be considered part of the control group (false) or in the experiment (true). If nil, the default behavior of checking the experiement ```:arm``` is applied.
|
|
53
|
+
|
|
54
|
+
## Data Types
|
|
27
55
|
|
|
28
|
-
|
|
56
|
+
### UserInfo
|
|
57
|
+
Basic information about the request user.
|
|
58
|
+
Field Name | Type | Optional? | Description
|
|
59
|
+
---------- | ---- | --------- | -----------
|
|
60
|
+
```:user_id``` | String | Yes | The platform user id, cleared from Promoted logs.
|
|
61
|
+
```:log_user_id``` | String | Yes | A different user id (presumably a UUID) disconnected from the platform user id, good for working with unauthenticated users or implementing right-to-be-forgotten.
|
|
29
62
|
|
|
30
|
-
|
|
63
|
+
---
|
|
64
|
+
### CohortMembership
|
|
65
|
+
Useful fields for experimentation during the delivery phase.
|
|
66
|
+
Field Name | Type | Optional? | Description
|
|
67
|
+
---------- | ---- | --------- | -----------
|
|
68
|
+
```:user_info``` | UserInfo | Yes | The user info structure.
|
|
69
|
+
```:arm``` | String | Yes | 'CONTROL' or one of the TREATMENT values (see [constants.rb](https://github.com/promotedai/promoted-ruby-client/blob/main/lib/promoted/ruby/client/constants.rb)).
|
|
70
|
+
---
|
|
71
|
+
### Properties
|
|
72
|
+
Properties bag. Has the structure:
|
|
31
73
|
|
|
32
|
-
|
|
74
|
+
```rb
|
|
75
|
+
:struct => {
|
|
76
|
+
:product => {
|
|
77
|
+
"id": "product3",
|
|
78
|
+
"title": "Product 3",
|
|
79
|
+
"url": "www.mymarket.com/p/3"
|
|
80
|
+
# other key-value pairs...
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
---
|
|
85
|
+
### Insertion
|
|
86
|
+
Content being served at a certain position.
|
|
87
|
+
Field Name | Type | Optional? | Description
|
|
88
|
+
---------- | ---- | --------- | -----------
|
|
89
|
+
```:user_info``` | UserInfo | Yes | The user info structure.
|
|
90
|
+
```:insertion_id``` | String | Yes | Generated by the SDK (*do not set*)
|
|
91
|
+
```:request_id``` | String | Yes | Generated by the SDK (*do not set*)
|
|
92
|
+
```:content_id``` | String | No | Identifier for the content to be shown, must be set.
|
|
93
|
+
```:properties``` | Properties | Yes | Any additional custom properties to associate. For v1 integrations, it is fine not to fill in all the properties.
|
|
33
94
|
|
|
34
|
-
|
|
95
|
+
---
|
|
96
|
+
### Paging
|
|
97
|
+
#### TODO
|
|
98
|
+
---
|
|
99
|
+
### Request
|
|
100
|
+
A request for content insertions.
|
|
101
|
+
Field Name | Type | Optional? | Description
|
|
102
|
+
---------- | ---- | --------- | -----------
|
|
103
|
+
```:user_info``` | UserInfo | Yes | The user info structure.
|
|
104
|
+
```:request_id``` | String | Yes | Generated by the SDK (*do not set*)
|
|
105
|
+
```:use_case``` | String | Yes | One of the use case values, i.e. 'FEED' (see [constants.rb](https://github.com/promotedai/promoted-ruby-client/blob/main/lib/promoted/ruby/client/constants.rb)).
|
|
106
|
+
```:properties``` | Properties | Yes | Any additional custom properties to associate.
|
|
107
|
+
```:paging``` | Paging | Yes | Paging parameters (see TODO)
|
|
108
|
+
---
|
|
109
|
+
### MetricsRequest
|
|
110
|
+
Input to ```prepare_for_logging```
|
|
111
|
+
Field Name | Type | Optional? | Description
|
|
112
|
+
---------- | ---- | --------- | -----------
|
|
113
|
+
```:request``` | Request | No | The underlying request for content.
|
|
114
|
+
```:full_insertion``` | [] of Insertion | No | The proposed list of insertions.
|
|
115
|
+
---
|
|
35
116
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
117
|
+
### DeliveryRequest
|
|
118
|
+
Input to ```deliver```
|
|
119
|
+
Field Name | Type | Optional? | Description
|
|
120
|
+
---------- | ---- | --------- | -----------
|
|
121
|
+
```:experiment``` | CohortMembership | Yes | A cohort to evaluation in experimentation.
|
|
122
|
+
```:request``` | Request | No | The underlying request for content.
|
|
123
|
+
```:full_insertion``` | [] of Insertion | No | The proposed list of insertions with all metadata, will be compacted before forwarding to Promoted.
|
|
124
|
+
```:only_log``` | Boolean | Yes | Defaults to false. Set to true to override whether Delivery API is called for this request.
|
|
125
|
+
---
|
|
40
126
|
|
|
41
|
-
|
|
127
|
+
### LogRequest
|
|
128
|
+
|
|
129
|
+
Output of ```prepare_for_logging``` as well as an ouput of an SDK call to ```deliver```, input to ```send_log_request``` to log to Promoted
|
|
130
|
+
Field Name | Type | Optional? | Description
|
|
131
|
+
---------- | ---- | --------- | -----------
|
|
132
|
+
```:request``` | Request | No | The underlying request for content to log.
|
|
133
|
+
```:insertion``` | [] of Insertion | No | The insertions, which are either the original request insertions or the insertions resulting from a call to ```deliver``` if such call occurred.
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### ClientResponse
|
|
137
|
+
Output of ```deliver```, includes the insertions as well as a suitable ```LogRequest``` for forwarding to Metrics API.
|
|
138
|
+
Field Name | Type | Optional? | Description
|
|
139
|
+
---------- | ---- | --------- | -----------
|
|
140
|
+
```:insertion``` | [] of Insertion | No | The insertions, which are from Delivery API (when ```deliver``` was called, i.e. we weren't either only-log or part of an experiment) or the input insertions (when the other conditions don't hold).
|
|
141
|
+
```:log_request``` | LogRequest | Yes | A message suitable for logging to Metrics API via ```send_log_request```. If the call to ```deliver``` was made (i.e. the request was not part of the CONTROL arm of an experiment or marked to only log), ```:log_request``` will not be set, as you can assume logging was performed on the server-side by Promoted.
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### PromotedClient
|
|
145
|
+
Method | Input | Output | Description
|
|
146
|
+
------ | ----- | ------ | -----------
|
|
147
|
+
```prepare_for_logging``` | MetricsRequest | LogRequest | Builds a request suitable for logging locally and/or to Promoted, either via a subsequent call to ```send_log_request``` in the SDK client or by using this structure to make the call yourself. Optionally, based on client configuration may send a random subset of requests to Delivery API as shadow traffic for integration purposes.
|
|
148
|
+
```send_log_request``` | LogRequest | n/a | Forwards a LogRequest to Promoted using an HTTP client.
|
|
149
|
+
```deliver``` | DeliveryRequest | ClientResponse | Makes a request (subject to experimentation) to Delivery API for insertions, which are then returned along with a LogRequest.
|
|
150
|
+
```close``` | n/a | n/a | Closes down the client at shutdown, currently this is just to drain the thread pool that handles shadow traffic.
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Metrics API
|
|
154
|
+
### Pagination
|
|
155
|
+
|
|
156
|
+
The `prepare_for_logging` call assumes the client has already handled pagination. It needs a `Request.paging.offset` to be passed in for the number of items deep that the page is.
|
|
157
|
+
TODO: Needs more details.
|
|
158
|
+
|
|
159
|
+
### Expected flow for Metrics logging
|
|
160
|
+
|
|
161
|
+
```rb
|
|
162
|
+
# Retrieve a list of content (i.e. products)
|
|
163
|
+
# products = fetch_my_marketplace_products()
|
|
42
164
|
|
|
43
|
-
```
|
|
44
165
|
products = [
|
|
45
166
|
{
|
|
46
167
|
id: "123",
|
|
@@ -62,136 +183,91 @@ products = [
|
|
|
62
183
|
}
|
|
63
184
|
]
|
|
64
185
|
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
186
|
+
# Transform them into an [] of Insertions.
|
|
187
|
+
insertions = products.map { |product|
|
|
188
|
+
{
|
|
189
|
+
:content_id => product[:id],
|
|
190
|
+
:properties => {
|
|
191
|
+
:struct => {
|
|
192
|
+
:type => product[:type],
|
|
193
|
+
:name => product[:name]
|
|
194
|
+
# etc
|
|
75
195
|
}
|
|
76
196
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
end
|
|
197
|
+
}
|
|
198
|
+
}
|
|
80
199
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
200
|
+
# Form a MetricsRequest
|
|
201
|
+
metrics_request = {
|
|
202
|
+
:request => {
|
|
203
|
+
:user_info => { :user_id => "912", :log_user_id => "912191"},
|
|
204
|
+
:use_case => "FEED",
|
|
205
|
+
:paging => {
|
|
206
|
+
:offset => 0,
|
|
207
|
+
:size => 5
|
|
88
208
|
},
|
|
89
|
-
properties
|
|
90
|
-
struct
|
|
91
|
-
active
|
|
209
|
+
:properties => {
|
|
210
|
+
:struct => {
|
|
211
|
+
:active => true
|
|
92
212
|
}
|
|
93
213
|
}
|
|
94
214
|
},
|
|
95
|
-
|
|
215
|
+
:full_insertion => insertions
|
|
96
216
|
}
|
|
97
217
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
218
|
+
# OPTIONAL: You can pass a custom function to "compact" insertions before metrics logging.
|
|
219
|
+
# Note that the PromotedClient has a class method helper, copy_and_remove_properties, that does just this.
|
|
220
|
+
to_compact_metrics_insertion_func = Proc.new do |insertion|
|
|
221
|
+
insertion.delete(:properties)
|
|
222
|
+
insertion
|
|
223
|
+
end
|
|
224
|
+
# metrics_request[:to_compact_metrics_insertion_func] = to_compact_metrics_insertion
|
|
101
225
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
=> "{\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"request\":[{\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"use_case\":\"FEED\",\"paging\":{\"from\":10,\"size\":10},\"properties\":{\"struct\":{\"active\":true}}}],\"insertion\":[{\"content_id\":\"123\",\"properties\":{\"struct\":{\"product\":{\"type\":\"SHOE\",\"name\":\"Blue shoe\",\"total_sales\":1000}}},\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"insertion_id\":\"a87e1b57-a574-424f-8af6-10e0250aa7ab\",\"request_id\":\"54ff4884-2192-4180-8c72-a805a436980f\",\"position\":10},{\"content_id\":\"124\",\"properties\":{\"struct\":{\"product\":{\"type\":\"SHIRT\",\"name\":\"Green shirt\",\"total_sales\":800}}},\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"insertion_id\":\"4495f72a-8101-4cb8-94ce-4db76839b8b6\",\"request_id\":\"54ff4884-2192-4180-8c72-a805a436980f\",\"position\":11},{\"content_id\":\"125\",\"properties\":{\"struct\":{\"product\":{\"type\":\"DRESS\",\"name\":\"Red dress\",\"total_sales\":1200}}},\"user_info\":{\"user_id\":\"912\",\"log_user_id\":\"912191\"},\"timing\":{\"client_log_timestamp\":1623306198},\"insertion_id\":\"d1e4f3f6-1783-4059-8fab-fdf2ba343cdf\",\"request_id\":\"54ff4884-2192-4180-8c72-a805a436980f\",\"position\":12}]}"
|
|
105
|
-
```
|
|
226
|
+
# Create a client
|
|
227
|
+
client = Promoted::Ruby::Client::PromotedClient.new
|
|
106
228
|
|
|
107
|
-
|
|
229
|
+
# Build a log request
|
|
230
|
+
log_request = client.prepare_for_logging(metrics_request)
|
|
108
231
|
|
|
109
|
-
|
|
232
|
+
# Log (assuming you have configured your client with a :metrics_endpoint)
|
|
233
|
+
client.send_log_request(log_request)
|
|
110
234
|
```
|
|
111
|
-
products = [
|
|
112
|
-
{
|
|
113
|
-
"id"=>"123",
|
|
114
|
-
"type"=>"SHOE",
|
|
115
|
-
"name"=>"Blue shoe",
|
|
116
|
-
"totalSales"=>1000
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
"id"=>"124",
|
|
120
|
-
"type"=>"SHIRT",
|
|
121
|
-
"name"=>"Green shirt",
|
|
122
|
-
"totalSales"=>800
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"id"=>"125",
|
|
126
|
-
"type"=>"DRESS",
|
|
127
|
-
"name"=>"Red dress",
|
|
128
|
-
"totalSales"=>1200
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
235
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
236
|
+
## Delivery API
|
|
237
|
+
|
|
238
|
+
### Expected flow for Delivery
|
|
239
|
+
|
|
240
|
+
```rb
|
|
241
|
+
# (continuing from the above example for Metrics)
|
|
242
|
+
|
|
243
|
+
# Form a DeliveryRequest
|
|
244
|
+
delivery_request = {
|
|
245
|
+
:request => {
|
|
246
|
+
:user_info => { :user_id => "912", :log_user_id => "912191"},
|
|
247
|
+
:use_case => "FEED",
|
|
248
|
+
:paging => {
|
|
249
|
+
:offset => 0,
|
|
250
|
+
:size => 5
|
|
251
|
+
},
|
|
252
|
+
:properties => {
|
|
253
|
+
:struct => {
|
|
254
|
+
:active => true
|
|
139
255
|
}
|
|
140
256
|
}
|
|
141
257
|
},
|
|
142
|
-
|
|
258
|
+
:full_insertion => insertions,
|
|
259
|
+
:only_log => false
|
|
143
260
|
}
|
|
144
|
-
```
|
|
145
261
|
|
|
146
|
-
|
|
262
|
+
# Request insertions from Delivery API
|
|
263
|
+
client_response = client.deliver(delivery_request)
|
|
264
|
+
|
|
265
|
+
# Use the resulting insertions
|
|
266
|
+
client_response[:insertion]
|
|
267
|
+
|
|
268
|
+
# Log if a log request was provided (if not, deliver was called successfully
|
|
269
|
+
# and Promoted logged on the server-side).)
|
|
270
|
+
client.send_log_request(client_response[:log_request]) if client_response[:log_request]
|
|
147
271
|
```
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
"user_info"=>{"user_id"=> "912", "log_user_id"=> "912191"},
|
|
151
|
-
"use_case"=>"FEED",
|
|
152
|
-
"properties"=>{
|
|
153
|
-
"struct"=>{
|
|
154
|
-
"active"=>true
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
"fullInsertion"=>[
|
|
159
|
-
{
|
|
160
|
-
"contentId"=>"123",
|
|
161
|
-
"properties"=>{
|
|
162
|
-
"struct"=>{
|
|
163
|
-
"product"=>{
|
|
164
|
-
"type"=>"SHOE",
|
|
165
|
-
"name"=>"Blue shoe",
|
|
166
|
-
"totalSales"=>1000
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"contentId"=>"124",
|
|
173
|
-
"properties"=>{
|
|
174
|
-
"struct"=>{
|
|
175
|
-
"product"=>{
|
|
176
|
-
"type"=>"SHIRT",
|
|
177
|
-
"name"=>"Green shirt",
|
|
178
|
-
"totalSales"=>800
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
"contentId"=>"125",
|
|
185
|
-
"properties"=>{
|
|
186
|
-
"struct"=>{
|
|
187
|
-
"product"=>{
|
|
188
|
-
"type"=>"DRESS",
|
|
189
|
-
"name"=>"Red dress",
|
|
190
|
-
"totalSales"=>1200
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
```
|
|
272
|
+
|
|
273
|
+
### TODO Experimentation example
|