promoted-ruby-client 0.1.0 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|