amplitude-api 0.1.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -4
- data/.rubocop.yml +19 -1
- data/.travis.yml +2 -3
- data/Changelog.md +32 -0
- data/Gemfile +3 -12
- data/Rakefile +7 -5
- data/amplitude-api.gemspec +17 -15
- data/lib/amplitude-api.rb +3 -4
- data/lib/amplitude_api.rb +71 -45
- data/lib/amplitude_api/config.rb +27 -5
- data/lib/amplitude_api/event.rb +77 -16
- data/lib/amplitude_api/identification.rb +3 -1
- data/lib/amplitude_api/version.rb +3 -1
- data/readme.md +38 -6
- data/spec/lib/amplitude_api/event_spec.rb +212 -112
- data/spec/lib/amplitude_api/identification_spec.rb +19 -17
- data/spec/lib/amplitude_api_spec.rb +328 -188
- data/spec/spec_helper.rb +7 -5
- metadata +6 -7
- data/Gemfile.lock +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4372cbca5a551be9721be89fbbe3ee80dc9216d8fa44fba7b0031a5e62785cd
|
4
|
+
data.tar.gz: ee6056b7e64c2b51f9365a8e57c90a1b4b8fc5edc406b1f7cbabf4caf831b7ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f55a3e558f985bac1d78ac842532dfd5dfc69290f7ece8f9c197c71f155ae802de8a00649c5be9bcdd4a67e995e59eaf9cbcc3586808ddfedbb00aba259cf39b
|
7
|
+
data.tar.gz: 3e6d679080a879ccf02ab29b3f13839b29c78bfb28cd48793275345ca41b77a61d09231e82d3cc4132319d14eef0ac807e5fa589330a1e0f84486fa534f875a4
|
data/.gitignore
CHANGED
@@ -27,11 +27,12 @@ build/
|
|
27
27
|
|
28
28
|
# for a library or gem, you might want to ignore these files since the code is
|
29
29
|
# intended to run in multiple environments; otherwise, check them in:
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
Gemfile.lock
|
31
|
+
.ruby-version
|
32
|
+
.ruby-gemset
|
33
33
|
|
34
34
|
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
35
|
.rvmrc
|
36
36
|
|
37
|
-
.idea
|
37
|
+
.idea
|
38
|
+
amplitude-api.iml
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,26 @@
|
|
1
1
|
require: rubocop-rspec
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: 2.4
|
5
|
+
|
2
6
|
Metrics/LineLength:
|
3
7
|
Max: 120
|
4
8
|
|
9
|
+
Style/StringLiterals:
|
10
|
+
EnforcedStyle: double_quotes
|
11
|
+
SupportedStyles:
|
12
|
+
- single_quotes
|
13
|
+
- double_quotes
|
14
|
+
|
15
|
+
Style/BlockDelimiters:
|
16
|
+
Enabled: true
|
17
|
+
Exclude:
|
18
|
+
- spec/**/*
|
19
|
+
|
5
20
|
# Disable some failing rspec cops that fail from upgrading gems until we can clean things up a bit.
|
21
|
+
Naming/FileName:
|
22
|
+
Exclude:
|
23
|
+
- lib/amplitude-api.rb
|
6
24
|
RSpec/ExampleLength:
|
7
25
|
Enabled: false
|
8
26
|
Metrics/BlockLength:
|
@@ -14,4 +32,4 @@ RSpec/NestedGroups:
|
|
14
32
|
RSpec/MessageSpies:
|
15
33
|
Enabled: false
|
16
34
|
RSpec/ContextWording:
|
17
|
-
Enabled: false
|
35
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
@@ -3,6 +3,38 @@
|
|
3
3
|
We would like to think our many [contributors](https://github.com/toothrot/amplitude-api/graphs/contributors) for
|
4
4
|
suggestions, ideas and improvements to Amplitude API.
|
5
5
|
|
6
|
+
## 0.3.3 (2021-02-24)
|
7
|
+
* Relaxes Faraday dependency
|
8
|
+
|
9
|
+
## 0.3.2 (2021-02-23)
|
10
|
+
* Creates new properties on initialization
|
11
|
+
|
12
|
+
## 0.3.1 (2021-02-23)
|
13
|
+
* Allows sending options to Amplitude
|
14
|
+
* Solves an error when accessing event properties not been created yet
|
15
|
+
|
16
|
+
## 0.3.0 (2021-02-22)
|
17
|
+
|
18
|
+
* Changes Typhoeus to Faraday to launch requests (**breaking change**)
|
19
|
+
* Adds new API fields to Event
|
20
|
+
* Event can now include arbitrary properties, so it could be used if the API adds new ones.
|
21
|
+
|
22
|
+
## 0.2.0 (2021-02-14)
|
23
|
+
|
24
|
+
* Updates gem to use HTTP API V2.
|
25
|
+
|
26
|
+
## 0.1.1 (2019-01-01)
|
27
|
+
|
28
|
+
* Fix #41 - Delete API now correctly handles Arrays of IDs.
|
29
|
+
|
30
|
+
## 0.1.0 (2019-01-01)
|
31
|
+
|
32
|
+
* Update Gem dependencies (thanks @kolorahl, @itamar, @krettan)
|
33
|
+
* Minimum ruby version is now 2.2
|
34
|
+
* Support Delete API (thanks @samjohn)
|
35
|
+
* Fix bundle Inline (thanks @jonduarte)
|
36
|
+
* Many fixes from @kolorahl
|
37
|
+
|
6
38
|
## 0.0.10 (2017-09-13)
|
7
39
|
|
8
40
|
* Allow to use "Event Segmentation" via API ([#23](https://github.com/toothrot/amplitude-api/pull/23)).
|
data/Gemfile
CHANGED
@@ -1,12 +1,3 @@
|
|
1
|
-
#
|
2
|
-
source
|
3
|
-
|
4
|
-
gem 'typhoeus', '~> 1.1'
|
5
|
-
|
6
|
-
group :development, :test do
|
7
|
-
gem 'pry', '~> 0.12.2'
|
8
|
-
gem 'rake', '>= 12.0'
|
9
|
-
gem 'rspec', '>= 2.99.0'
|
10
|
-
gem 'rubocop', '~> 0.66.0', require: false
|
11
|
-
gem 'rubocop-rspec'
|
12
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
source "https://rubygems.org"
|
3
|
+
gemspec
|
data/Rakefile
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rubocop/rake_task"
|
3
5
|
|
4
6
|
RuboCop::RakeTask.new
|
5
7
|
|
6
8
|
begin
|
7
|
-
require
|
9
|
+
require "rspec/core/rake_task"
|
8
10
|
RSpec::Core::RakeTask.new(:spec)
|
9
11
|
rescue LoadError
|
10
|
-
puts
|
12
|
+
puts "Unable to load rspec. Have you run `bundle install`?"
|
11
13
|
end
|
12
14
|
|
13
15
|
task(:default).clear
|
14
|
-
task default: [
|
16
|
+
task default: ["rubocop:auto_correct", :spec]
|
data/amplitude-api.gemspec
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require
|
5
|
+
require "amplitude_api/version"
|
4
6
|
|
5
7
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
8
|
+
spec.name = "amplitude-api"
|
7
9
|
spec.version = AmplitudeAPI::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
10
|
-
spec.summary =
|
11
|
-
spec.description =
|
12
|
-
spec.homepage =
|
13
|
-
spec.license =
|
10
|
+
spec.authors = ["Alex Rakoczy"]
|
11
|
+
spec.email = ["arakoczy@gmail.com"]
|
12
|
+
spec.summary = "Send events to the Amplitude API"
|
13
|
+
spec.description = "Provides an integration for sending events to Amplitude"
|
14
|
+
spec.homepage = "https://github.com/toothrot/amplitude-api"
|
15
|
+
spec.license = "MIT"
|
14
16
|
|
15
17
|
spec.files = `git ls-files -z`.split("\x0")
|
16
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ["lib"]
|
19
21
|
|
20
|
-
spec.add_development_dependency
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_dependency
|
24
|
-
spec.required_ruby_version =
|
22
|
+
spec.add_development_dependency "pry", "~> 0.12.2"
|
23
|
+
spec.add_development_dependency "rake", "~> 12.0", ">= 12.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.99", ">= 2.99.0"
|
25
|
+
spec.add_dependency "faraday", "~> 1.0"
|
26
|
+
spec.required_ruby_version = ">= 2.4"
|
25
27
|
end
|
data/lib/amplitude-api.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
# Whoops.
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "amplitude_api"
|
data/lib/amplitude_api.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "faraday"
|
3
5
|
|
4
6
|
# AmplitudeAPI
|
5
7
|
class AmplitudeAPI
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
8
|
+
require_relative "amplitude_api/config"
|
9
|
+
require_relative "amplitude_api/event"
|
10
|
+
require_relative "amplitude_api/identification"
|
9
11
|
|
10
|
-
TRACK_URI_STRING =
|
11
|
-
IDENTIFY_URI_STRING =
|
12
|
-
SEGMENTATION_URI_STRING =
|
13
|
-
DELETION_URI_STRING =
|
12
|
+
TRACK_URI_STRING = "https://api.amplitude.com/2/httpapi"
|
13
|
+
IDENTIFY_URI_STRING = "https://api.amplitude.com/identify"
|
14
|
+
SEGMENTATION_URI_STRING = "https://amplitude.com/api/2/events/segmentation"
|
15
|
+
DELETION_URI_STRING = "https://amplitude.com/api/2/deletions/users"
|
14
16
|
|
15
|
-
USER_WITH_NO_ACCOUNT = "user who doesn't have an account"
|
17
|
+
USER_WITH_NO_ACCOUNT = "user who doesn't have an account"
|
16
18
|
|
17
19
|
class << self
|
18
20
|
def config
|
@@ -38,12 +40,12 @@ class AmplitudeAPI
|
|
38
40
|
# @param [ String ] event_name a string that describes the event, e.g. "clicked on Home"
|
39
41
|
# @param [ String ] user a string or integer that uniquely identifies a user.
|
40
42
|
# @param [ String ] device a string that uniquely identifies the device.
|
41
|
-
# @
|
43
|
+
# @option options [ Hash ] event_properties a hash that is serialized to JSON,
|
42
44
|
# and can contain any other property to be stored on the Event
|
43
|
-
# @
|
45
|
+
# @option options [ Hash ] user_properties a hash that is serialized to JSON,
|
44
46
|
# and contains user properties to be associated with the user
|
45
47
|
#
|
46
|
-
# @return [
|
48
|
+
# @return [ Faraday::Response ]
|
47
49
|
def send_event(event_name, user, device, options = {})
|
48
50
|
event = AmplitudeAPI::Event.new(
|
49
51
|
user_id: user,
|
@@ -68,10 +70,13 @@ class AmplitudeAPI
|
|
68
70
|
def track_body(*events)
|
69
71
|
event_body = events.flatten.map(&:to_hash)
|
70
72
|
|
71
|
-
{
|
73
|
+
body = {
|
72
74
|
api_key: api_key,
|
73
|
-
|
75
|
+
events: event_body
|
74
76
|
}
|
77
|
+
body[:options] = config.options if config.options
|
78
|
+
|
79
|
+
JSON.generate(body)
|
75
80
|
end
|
76
81
|
|
77
82
|
# @overload track(event)
|
@@ -80,11 +85,11 @@ class AmplitudeAPI
|
|
80
85
|
# @overload track([events])
|
81
86
|
# @param [ Array<AmplitudeAPI::Event> ] Send an array of events in a single request to Amplitude
|
82
87
|
#
|
83
|
-
# @return [
|
88
|
+
# @return [ Faraday::Response ]
|
84
89
|
#
|
85
90
|
# Send one or more Events to the Amplitude API
|
86
91
|
def track(*events)
|
87
|
-
|
92
|
+
Faraday.post(TRACK_URI_STRING, track_body(events), "Content-Type" => "application/json")
|
88
93
|
end
|
89
94
|
|
90
95
|
# ==== Identification related methods
|
@@ -123,40 +128,40 @@ class AmplitudeAPI
|
|
123
128
|
# @overload identify([identifications])
|
124
129
|
# @param [ Array<AmplitudeAPI::Identify> ] Send an array of identifications in a single request to Amplitude
|
125
130
|
#
|
126
|
-
# @return [
|
131
|
+
# @return [ Faraday::Response ]
|
127
132
|
#
|
128
133
|
# Send one or more Identifications to the Amplitude Identify API
|
129
134
|
def identify(*identifications)
|
130
|
-
|
135
|
+
Faraday.post(IDENTIFY_URI_STRING, identify_body(identifications))
|
131
136
|
end
|
132
137
|
|
133
138
|
# ==== Event Segmentation related methods
|
134
139
|
|
135
140
|
# Get metrics for an event with segmentation.
|
136
141
|
#
|
137
|
-
# @param [ Hash ]
|
142
|
+
# @param [ Hash ] event a hash that defines event.
|
138
143
|
# @param [ Time ] start_time a start time.
|
139
144
|
# @param [ Time ] end_time a end time.
|
140
|
-
# @
|
145
|
+
# @option options [ String ] m a string that defines aggregate function.
|
141
146
|
# For non-property metrics: "uniques", "totals", "pct_dau", or "average" (default: "uniques").
|
142
147
|
# For property metrics: "histogram", "sums", or "value_avg"
|
143
148
|
# (note: a valid "group_by" value is required in parameter e).
|
144
|
-
# @
|
149
|
+
# @option options [ Integer ] i an integer that defines segmentation interval.
|
145
150
|
# Set to -300000, -3600000, 1, 7, or 30 for realtime, hourly, daily, weekly,
|
146
151
|
# and monthly counts, respectively (default: 1). Realtime segmentation is capped at 2 days,
|
147
152
|
# hourly segmentation is capped at 7 days, and daily at 365 days.
|
148
|
-
# @
|
149
|
-
# @
|
150
|
-
# @
|
153
|
+
# @option options [ Array ] s an array that defines segment definitions.
|
154
|
+
# @option options [ String ] g a string that defines property to group by.
|
155
|
+
# @option options [ Integer ] limit an integer that defines number of Group By values
|
151
156
|
# returned (default: 100). The maximum limit is 1000.
|
152
157
|
#
|
153
|
-
# @return [
|
158
|
+
# @return [ Faraday::Response ]
|
154
159
|
def segmentation(event, start_time, end_time, **options)
|
155
|
-
|
160
|
+
Faraday.get SEGMENTATION_URI_STRING, userpwd: "#{api_key}:#{secret_key}", params: {
|
156
161
|
e: event.to_json,
|
157
162
|
m: options[:m],
|
158
|
-
start: start_time.strftime(
|
159
|
-
end: end_time.strftime(
|
163
|
+
start: start_time.strftime("%Y%m%d"),
|
164
|
+
end: end_time.strftime("%Y%m%d"),
|
160
165
|
i: options[:i],
|
161
166
|
s: (options[:s] || []).map(&:to_json),
|
162
167
|
g: options[:g],
|
@@ -164,27 +169,48 @@ class AmplitudeAPI
|
|
164
169
|
}.delete_if { |_, value| value.nil? }
|
165
170
|
end
|
166
171
|
|
167
|
-
#
|
168
|
-
|
169
|
-
# Delete a user from amplitude when they request it to comply with GDPR
|
172
|
+
# Delete a user from amplitude
|
173
|
+
#
|
170
174
|
# You must pass in either an array of user_ids or an array of amplitude_ids
|
171
175
|
#
|
172
|
-
# @param [
|
176
|
+
# @param [ Array<String> ] (optional) the user_ids to delete
|
173
177
|
# based on your database
|
174
|
-
# @param [
|
178
|
+
# @param [ Array<Integer> ] (optional) the amplitude_ids to delete
|
175
179
|
# based on the amplitude database
|
176
|
-
# @param [
|
180
|
+
# @param [ String ] requester the email address of the person who
|
177
181
|
# is requesting the deletion, optional but useful for reporting
|
178
|
-
#
|
179
|
-
#
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
182
|
+
# @param [ Boolean ] (optional) ignore any invalid user IDs(users that do no
|
183
|
+
# exist in the project) that were passed in
|
184
|
+
# @param [ Boolean ] (optional) delete from the entire org rather than just
|
185
|
+
# this project.
|
186
|
+
# @return [ Faraday::Response ]
|
187
|
+
def delete(user_ids: nil, amplitude_ids: nil, requester: nil, ignore_invalid_id: nil, delete_from_org: nil)
|
188
|
+
user_ids = Array(user_ids)
|
189
|
+
amplitude_ids = Array(amplitude_ids)
|
190
|
+
|
191
|
+
faraday = Faraday.new do |conn|
|
192
|
+
conn.basic_auth config.api_key, config.secret_key
|
193
|
+
end
|
194
|
+
|
195
|
+
faraday.post(
|
196
|
+
DELETION_URI_STRING,
|
197
|
+
delete_body(user_ids, amplitude_ids, requester, ignore_invalid_id, delete_from_org),
|
198
|
+
"Content-Type" => "application/json"
|
199
|
+
)
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
def delete_body(user_ids, amplitude_ids, requester, ignore_invalid_id, delete_from_org)
|
205
|
+
body = {
|
206
|
+
amplitude_ids: amplitude_ids,
|
207
|
+
user_ids: user_ids,
|
208
|
+
requester: requester
|
209
|
+
}.delete_if { |_, value| value.nil? || value.empty? }
|
210
|
+
|
211
|
+
body[:ignore_invalid_id] = ignore_invalid_id.to_s if ignore_invalid_id
|
212
|
+
body[:delete_from_org] = delete_from_org.to_s if delete_from_org
|
213
|
+
JSON.generate(body)
|
188
214
|
end
|
189
215
|
end
|
190
216
|
end
|
data/lib/amplitude_api/config.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
2
4
|
|
3
5
|
class AmplitudeAPI
|
4
6
|
# AmplitudeAPI::Config
|
@@ -6,20 +8,40 @@ class AmplitudeAPI
|
|
6
8
|
include Singleton
|
7
9
|
|
8
10
|
attr_accessor :api_key, :secret_key, :whitelist, :time_formatter,
|
9
|
-
:event_properties_formatter, :user_properties_formatter
|
11
|
+
:event_properties_formatter, :user_properties_formatter,
|
12
|
+
:options
|
10
13
|
|
11
14
|
def initialize
|
12
15
|
self.class.defaults.each { |k, v| send("#{k}=", v) }
|
13
16
|
end
|
14
17
|
|
15
18
|
class << self
|
19
|
+
def base_properties
|
20
|
+
%i[event_type event_properties user_properties user_id device_id]
|
21
|
+
end
|
22
|
+
|
23
|
+
def revenue_properties
|
24
|
+
%i[revenue_type product_id revenue price quantity]
|
25
|
+
end
|
26
|
+
|
27
|
+
def optional_properties
|
28
|
+
%i[
|
29
|
+
time
|
30
|
+
ip platform country insert_id
|
31
|
+
groups app_version os_name os_version
|
32
|
+
device_brand device_manufacturer device_model
|
33
|
+
carrier region city dma language
|
34
|
+
location_lat location_lng
|
35
|
+
idfa idfv adid android_id
|
36
|
+
event_id session_id
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
16
40
|
def defaults
|
17
41
|
{
|
18
42
|
api_key: nil,
|
19
43
|
secret_key: nil,
|
20
|
-
whitelist:
|
21
|
-
event_properties user_properties time ip platform country insert_id
|
22
|
-
revenue_type price quantity product_id],
|
44
|
+
whitelist: base_properties + revenue_properties + optional_properties,
|
23
45
|
time_formatter: ->(time) { time ? time.to_i * 1_000 : nil },
|
24
46
|
event_properties_formatter: ->(props) { props || {} },
|
25
47
|
user_properties_formatter: ->(props) { props || {} }
|