Skip to content

Commit 288aec1

Browse files
committed
Merge pull request #7 from jponc/feature/add-identify
Add Identify API
2 parents 7f5e6e2 + 528a4f5 commit 288aec1

File tree

4 files changed

+204
-11
lines changed

4 files changed

+204
-11
lines changed

lib/amplitude-api.rb

+55-7
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
require 'bundler/setup'
33
require 'typhoeus'
44
require 'amplitude-api/event'
5+
require 'amplitude-api/identification'
56

67
class AmplitudeAPI
7-
URI_STRING = "https://api.amplitude.com/httpapi"
8+
TRACK_URI_STRING = "https://api.amplitude.com/httpapi"
9+
IDENTIFY_URI_STRING = "https://api.amplitude.com/identify"
810

911
USER_WITH_NO_ACCOUNT = "user who doesn't have an account"
1012

@@ -13,6 +15,8 @@ class << self
1315
# @return [ String ] an Amplitude API Key
1416
attr_accessor :api_key
1517

18+
# ==== Event Tracking related methods
19+
1620
# Send a single event immediately to the AmplitudeAPI
1721
#
1822
# @param [ String ] event_name a string that describes the event, e.g. "clicked on Home"
@@ -25,37 +29,81 @@ def send_event(event_name, user, properties = {})
2529
track(event)
2630
end
2731

28-
# @overload body(event)
32+
33+
# @overload track_body(event)
2934
# @param [ AmplitudeAPI::Event ]
3035
#
31-
# @overload body([events])
36+
# @overload track_body([events])
3237
# @param [ Array<AmplitudeAPI::Event> ]
3338
#
3439
# @return [ Hash ]
3540
#
3641
# Converts a series of AmplitudeAPI::Event objects into a body
3742
# suitable for the Amplitude API
38-
def body(*events)
43+
def track_body(*events)
3944
event_body = events.flatten.map do |event|
4045
event.to_hash
4146
end
42-
post_body = {
47+
48+
{
4349
api_key: self.api_key,
4450
event: JSON.generate(event_body)
4551
}
4652
end
4753

54+
4855
# @overload track(event)
4956
# @param [ AmplitudeAPI::Event ] Send a single event to the Amplitude API
5057
#
5158
# @overload track([events])
5259
# @param [ Array<AmplitudeAPI::Event> ] Send an array of events in a single request to Amplitude
5360
#
54-
# @return [ Typhoeus::Response ]
61+
# @return [ Typhoeus::Response ]
5562
#
5663
# Send one or more Events to the Amplitude API
5764
def track(*events)
58-
Typhoeus.post(URI_STRING, body: body(events))
65+
Typhoeus.post(TRACK_URI_STRING, body: track_body(events))
66+
end
67+
68+
# ==== Identification related methods
69+
70+
def send_identify(user_id, user_properties = {})
71+
identification = AmplitudeAPI::Identification.new(user_id: user_id, user_properties: user_properties)
72+
identify(identification)
73+
end
74+
75+
# @overload identify_body(identification)
76+
# @param [ AmplitudeAPI::Identification ]
77+
#
78+
# @overload identify_body([identifications])
79+
# @param [ Array<AmplitudeAPI::Identification> ]
80+
#
81+
# @return [ Hash ]
82+
#
83+
# Converts a series of AmplitudeAPI::Identification objects into a body
84+
# suitable for the Amplitude Identify API
85+
def identify_body(*identifications)
86+
identification_body = identifications.flatten.map do |identification|
87+
identification.to_hash
88+
end
89+
90+
{
91+
api_key: self.api_key,
92+
identification: JSON.generate(identification_body)
93+
}
94+
end
95+
96+
# @overload identify(identification)
97+
# @param [ AmplitudeAPI::Identify ] Send a single identify to the Amplitude API
98+
#
99+
# @overload identify([identifications])
100+
# @param [ Array<AmplitudeAPI::Identify> ] Send an array of identifications in a single request to Amplitude
101+
#
102+
# @return [ Typhoeus::Response ]
103+
#
104+
# Send one or more Identifications to the Amplitude Identify API
105+
def identify(*identifications)
106+
Typhoeus.post(IDENTIFY_URI_STRING, body: identify_body(identifications))
59107
end
60108
end
61109
end

lib/amplitude-api/identification.rb

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
class AmplitudeAPI
2+
class Identification
3+
# @!attribute [ rw ] user_id
4+
# @return [ String ] the user_id to be sent to Amplitude
5+
attr_accessor :user_id
6+
# @!attribute [ rw ] user_properties
7+
# @return [ String ] the user_properties to be attached to the Amplitude Identify
8+
attr_accessor :user_properties
9+
10+
# Create a new Identification
11+
#
12+
# @param [ String ] user_id a user_id to associate with the identification
13+
# @param [ Hash ] user_properties various properties to attach to the user identification
14+
def initialize(user_id: "", user_properties: {})
15+
self.user_id = user_id
16+
self.user_properties = user_properties
17+
end
18+
19+
def user_id=(value)
20+
@user_id =
21+
if value.respond_to?(:id)
22+
value.id
23+
else
24+
value || AmplitudeAPI::USER_WITH_NO_ACCOUNT
25+
end
26+
end
27+
28+
# @return [ Hash ] A serialized Event
29+
#
30+
# Used for serialization and comparison
31+
def to_hash
32+
{
33+
user_id: self.user_id,
34+
user_properties: self.user_properties
35+
}
36+
end
37+
38+
# @return [ true, false ]
39+
#
40+
# Compares +to_hash+ for equality
41+
def ==(other)
42+
if other.respond_to?(:to_hash)
43+
self.to_hash == other.to_hash
44+
else
45+
false
46+
end
47+
end
48+
end
49+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
require 'spec_helper'
2+
3+
describe AmplitudeAPI::Identification do
4+
User = Struct.new(:id)
5+
6+
context "with a user object" do
7+
describe "#body" do
8+
it "populates with the user's id" do
9+
identification = AmplitudeAPI::Identification.new(user_id: User.new(123))
10+
expect(identification.to_hash[:user_id]).to eq(123)
11+
end
12+
end
13+
end
14+
15+
context "with a user id" do
16+
describe "#body" do
17+
it "populates with the user's id" do
18+
identification = AmplitudeAPI::Identification.new(user_id: 123)
19+
expect(identification.to_hash[:user_id]).to eq(123)
20+
end
21+
end
22+
end
23+
24+
context "without a user" do
25+
describe "#body" do
26+
it "populates with the unknown user" do
27+
identification = AmplitudeAPI::Identification.new(user_id: nil)
28+
expect(identification.to_hash[:user_id]).to eq(AmplitudeAPI::USER_WITH_NO_ACCOUNT)
29+
end
30+
end
31+
end
32+
33+
describe '#body' do
34+
it "includes the user id" do
35+
identification = AmplitudeAPI::Identification.new(user_id: 123)
36+
expect(identification.to_hash[:user_id]).to eq(123)
37+
end
38+
39+
it "includes arbitrary user properties" do
40+
identification = AmplitudeAPI::Identification.new(user_id: 123, user_properties: {first_name: 'John', last_name: 'Doe'})
41+
expect(identification.to_hash[:user_properties]).to eq(first_name: 'John', last_name: 'Doe')
42+
end
43+
end
44+
end

spec/lib/amplitude_api_spec.rb

+56-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
event = AmplitudeAPI::Event.new(user_id: 123, event_type: 'clicked on sign up')
1212
body = {api_key: AmplitudeAPI.api_key, event: JSON.generate([event.to_hash])}
1313

14-
expect(Typhoeus).to receive(:post).with(AmplitudeAPI::URI_STRING, body: body)
14+
expect(Typhoeus).to receive(:post).with(AmplitudeAPI::TRACK_URI_STRING, body: body)
1515

1616
AmplitudeAPI.track(event)
1717
end
@@ -23,13 +23,38 @@
2323
event2 = AmplitudeAPI::Event.new(user_id: 456, event_type: 'liked a widget')
2424
body = {api_key: AmplitudeAPI.api_key, event: JSON.generate([event.to_hash, event2.to_hash])}
2525

26-
expect(Typhoeus).to receive(:post).with(AmplitudeAPI::URI_STRING, body: body)
26+
expect(Typhoeus).to receive(:post).with(AmplitudeAPI::TRACK_URI_STRING, body: body)
2727

2828
AmplitudeAPI.track([event, event2])
2929
end
3030
end
3131
end
3232

33+
describe ".identify" do
34+
context "with a single identification" do
35+
it "sends the identification to Amplitude" do
36+
identification = AmplitudeAPI::Identification.new(user_id: 123, user_properties: {first_name: 'John', last_name: 'Doe'})
37+
body = {api_key: AmplitudeAPI.api_key, identification: JSON.generate([identification.to_hash])}
38+
39+
expect(Typhoeus).to receive(:post).with(AmplitudeAPI::IDENTIFY_URI_STRING, body: body)
40+
41+
AmplitudeAPI.identify(identification)
42+
end
43+
end
44+
45+
context "with multiple identifications" do
46+
it "sends all identifications in a single request" do
47+
identification = AmplitudeAPI::Identification.new(user_id: 123, user_properties: {first_name: 'Julian', last_name: 'Ponce'})
48+
identification2 = AmplitudeAPI::Identification.new(user_id: 456, user_properties: {first_name: 'John', last_name: 'Doe'})
49+
body = {api_key: AmplitudeAPI.api_key, identification: JSON.generate([identification.to_hash, identification2.to_hash])}
50+
51+
expect(Typhoeus).to receive(:post).with(AmplitudeAPI::IDENTIFY_URI_STRING, body: body)
52+
53+
AmplitudeAPI.identify([identification, identification2])
54+
end
55+
end
56+
end
57+
3358
describe ".initializer " do
3459
it "initializes event without parameter" do
3560
event = AmplitudeAPI::Event.new()
@@ -77,16 +102,43 @@
77102
end
78103
end
79104

105+
describe ".send_identify" do
106+
it "sends an identify to AmplitudeAPI" do
107+
identification = AmplitudeAPI::Identification.new(user_id: @user, user_properties: {first_name: 'John', last_name: 'Doe'})
108+
expect(AmplitudeAPI).to receive(:identify).with(identification)
109+
110+
AmplitudeAPI.send_identify(@user, {first_name: 'John', last_name: 'Doe'})
111+
end
112+
113+
context "the user is nil" do
114+
it "sends an identify with the no account user" do
115+
identification = AmplitudeAPI::Identification.new(user_id: nil, user_properties: {first_name: 'John', last_name: 'Doe'})
116+
expect(AmplitudeAPI).to receive(:identify).with(identification)
117+
118+
AmplitudeAPI.send_identify(nil, {first_name: 'John', last_name: 'Doe'})
119+
end
120+
end
121+
122+
context "the user is a user_id" do
123+
it "sends an identify to AmplitudeAPI" do
124+
identification = AmplitudeAPI::Identification.new(user_id: 123, user_properties: {first_name: 'John', last_name: 'Doe'})
125+
expect(AmplitudeAPI).to receive(:identify).with(identification)
126+
127+
AmplitudeAPI.send_identify(@user.id, {first_name: 'John', last_name: 'Doe'})
128+
end
129+
end
130+
end
131+
80132
describe "#body" do
81133
it "should add an api key" do
82134
event = AmplitudeAPI::Event.new(user_id: @user, event_type: "test_event", event_properties: {test_property: 1})
83-
body = AmplitudeAPI.body(event)
135+
body = AmplitudeAPI.track_body(event)
84136
expect(body[:api_key]).to eq('stub api key')
85137
end
86138

87139
it "should create an event" do
88140
event = AmplitudeAPI::Event.new(user_id: 23, event_type: "test_event", event_properties: {foo: "bar"})
89-
body = AmplitudeAPI.body(event)
141+
body = AmplitudeAPI.track_body(event)
90142

91143
expected = JSON.generate([{event_type: "test_event", user_id: 23, event_properties: {foo: "bar"}}])
92144
expect(body[:event]).to eq(expected)

0 commit comments

Comments
 (0)