fitgem_oauth2 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/fitgem_oauth2.gemspec +22 -22
- data/lib/fitgem_oauth2.rb +6 -6
- data/lib/fitgem_oauth2/activity.rb +209 -209
- data/lib/fitgem_oauth2/body_measurements.rb +163 -163
- data/lib/fitgem_oauth2/client.rb +126 -126
- data/lib/fitgem_oauth2/devices.rb +45 -45
- data/lib/fitgem_oauth2/errors.rb +30 -30
- data/lib/fitgem_oauth2/food.rb +27 -27
- data/lib/fitgem_oauth2/food/collection.rb +51 -51
- data/lib/fitgem_oauth2/food/metadata.rb +63 -63
- data/lib/fitgem_oauth2/food/series.rb +55 -55
- data/lib/fitgem_oauth2/friends.rb +44 -44
- data/lib/fitgem_oauth2/heartrate.rb +85 -85
- data/lib/fitgem_oauth2/sleep.rb +86 -86
- data/lib/fitgem_oauth2/subscriptions.rb +32 -32
- data/lib/fitgem_oauth2/users.rb +7 -7
- data/lib/fitgem_oauth2/utils.rb +48 -48
- data/lib/fitgem_oauth2/version.rb +3 -3
- metadata +5 -5
@@ -1,163 +1,163 @@
|
|
1
|
-
module FitgemOauth2
|
2
|
-
class Client
|
3
|
-
FAT_PERIODS = %w(1d 7d 1w 1m)
|
4
|
-
WEIGHT_PERIODS = %w(1d 7d 30d 1w 1m)
|
5
|
-
BODY_GOALS = %w(fat weight)
|
6
|
-
BODY_TIME_SERIES_PERIODS = %w(1d 7d 30d 1w 1m 3m 6m 1y max)
|
7
|
-
|
8
|
-
# ======================================
|
9
|
-
# Boday Fat
|
10
|
-
# ======================================
|
11
|
-
|
12
|
-
# retrieves a list of all user's body fat log entries
|
13
|
-
# note: provide either end_date or period
|
14
|
-
# @param start_date start date for the logs
|
15
|
-
# @param end_date (optional)end date for the logs
|
16
|
-
# @param period (optional) period for the logs
|
17
|
-
def body_fat_logs(start_date: nil, end_date: nil, period: nil)
|
18
|
-
unless start_date
|
19
|
-
raise FitgemOauth2::InvalidArgumentError, 'must specify start_date'
|
20
|
-
end
|
21
|
-
url = ['user', user_id, 'body/log/fat/date', format_date(start_date)].join('/')
|
22
|
-
if end_date
|
23
|
-
url = [url, format_date(end_date)].join('/')
|
24
|
-
end
|
25
|
-
|
26
|
-
if period
|
27
|
-
if FAT_PERIODS.include?(period)
|
28
|
-
url = [url, period].join('/')
|
29
|
-
else
|
30
|
-
raise FitgemOauth2::InvalidArgumentError, "period must be one in #{FAT_PERIODS}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
url = url + '.json'
|
35
|
-
|
36
|
-
get_call(url)
|
37
|
-
end
|
38
|
-
|
39
|
-
# logs body fat
|
40
|
-
# @param params POST parameters for logging body fat
|
41
|
-
def log_body_fat(params)
|
42
|
-
post_call("user/#{user_id}/body/log/fat.json", params)
|
43
|
-
end
|
44
|
-
|
45
|
-
# delete logged body fat
|
46
|
-
# @param id ID of the log to be deleted.
|
47
|
-
def delete_logged_body_fat(id)
|
48
|
-
delete_call("user/#{user_id}/body/log/fat/#{id}.json")
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
# ==================================
|
53
|
-
# Body Time Series
|
54
|
-
# ==================================
|
55
|
-
|
56
|
-
# retrieve body time series for the user; provide at least one of end_date and period
|
57
|
-
# @param resource (required)the resource requested ['bmi', 'fat', or 'weight']
|
58
|
-
# @param start_date (required)the start date for the series
|
59
|
-
# @param end_date (optional)the end date for the series
|
60
|
-
# @param period (optional)period for the time series. valid periods are BODY_TIME_SERIES_PERIODS
|
61
|
-
def body_time_series(resource: nil, start_date: nil, end_date: nil, period: nil)
|
62
|
-
unless resource && start_date
|
63
|
-
raise FitgemOauth2::InvalidArgumentError, 'resource and start_date are required parameters. Please specify both.'
|
64
|
-
end
|
65
|
-
|
66
|
-
url = ['user', user_id, 'body', resource, 'date', format_date(start_date)].join('/')
|
67
|
-
|
68
|
-
second = ''
|
69
|
-
if end_date && period
|
70
|
-
raise FitgemOauth2::InvalidArgumentError, 'Please specify either period or end date, not both.'
|
71
|
-
end
|
72
|
-
|
73
|
-
if period
|
74
|
-
if BODY_TIME_SERIES_PERIODS.include?(period)
|
75
|
-
second = period
|
76
|
-
else
|
77
|
-
raise FitgemOauth2::InvalidArgumentError, "Invalid Period. Body time series period must be in #{BODY_TIME_SERIES_PERIODS}"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
if end_date
|
82
|
-
second = format_date(end_date)
|
83
|
-
end
|
84
|
-
|
85
|
-
url = [url, second].join('/')
|
86
|
-
|
87
|
-
get_call(url + '.json')
|
88
|
-
end
|
89
|
-
|
90
|
-
|
91
|
-
# ======================================
|
92
|
-
# Body Goals
|
93
|
-
# ======================================
|
94
|
-
|
95
|
-
# retrieves body goals based on the type specified
|
96
|
-
# @param type 'fat' or 'weight'
|
97
|
-
def body_goals(type)
|
98
|
-
if type && BODY_GOALS.include?(type)
|
99
|
-
get_call("user/#{user_id}/body/log/#{type}/goal.json")
|
100
|
-
else
|
101
|
-
raise FitgemOauth2::InvalidArgumentError, "invalid goal type : #{type}. must be one of #{BODY_GOALS}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# update body fat goal
|
106
|
-
# @param params POST params for updating body fat goal
|
107
|
-
def update_body_fat_goal(params)
|
108
|
-
post_call("user/#{user_id}/body/log/fat/goal.json", params)
|
109
|
-
end
|
110
|
-
|
111
|
-
# update weight goal
|
112
|
-
# @param params POST params for updating weight goal
|
113
|
-
def update_weight_goal(params)
|
114
|
-
post_call("user/#{user_id}/body/log/weight/goal.json", params)
|
115
|
-
end
|
116
|
-
|
117
|
-
# ======================================
|
118
|
-
# Body Weight
|
119
|
-
# ======================================
|
120
|
-
|
121
|
-
# retrieve weight logs; specify either the end_date or period
|
122
|
-
# @param start_date start date for the logs
|
123
|
-
# @param end_date (optional)end_date for the logs
|
124
|
-
# @param period (optional)period for the logs
|
125
|
-
def weight_logs(start_date: nil, end_date: nil, period: nil)
|
126
|
-
unless start_date
|
127
|
-
raise FitgemOauth2::InvalidArgumentError, 'start_date not specified.'
|
128
|
-
end
|
129
|
-
|
130
|
-
if period && end_date
|
131
|
-
raise FitgemOauth2::InvalidArgumentError, 'both end_date and period specified. please provide only one.'
|
132
|
-
end
|
133
|
-
|
134
|
-
if period
|
135
|
-
unless WEIGHT_PERIODS.include?(period)
|
136
|
-
raise FitgemOauth2::InvalidArgumentError, "valid period not specified. please choose a period from #{WEIGHT_PERIODS}"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
first = format_date(start_date)
|
141
|
-
url = ['user', user_id, 'body/log/weight/date', first].join('/')
|
142
|
-
if period || end_date
|
143
|
-
second = period || format_date(end_date)
|
144
|
-
url = [url, second].join('/')
|
145
|
-
end
|
146
|
-
|
147
|
-
get_call(url + '.json')
|
148
|
-
end
|
149
|
-
|
150
|
-
# logs weight for the user
|
151
|
-
# @param params POST message for logging weight
|
152
|
-
def log_weight(params)
|
153
|
-
post_call("user/#{user_id}/body/log/weight.json", params)
|
154
|
-
end
|
155
|
-
|
156
|
-
# delete logged weight
|
157
|
-
# @param id ID of the weight log to be deleted
|
158
|
-
def delete_logged_weight(id)
|
159
|
-
delete_call("user/#{user_id}/body/log/weight/#{id}.json")
|
160
|
-
end
|
161
|
-
|
162
|
-
end
|
163
|
-
end
|
1
|
+
module FitgemOauth2
|
2
|
+
class Client
|
3
|
+
FAT_PERIODS = %w(1d 7d 1w 1m)
|
4
|
+
WEIGHT_PERIODS = %w(1d 7d 30d 1w 1m)
|
5
|
+
BODY_GOALS = %w(fat weight)
|
6
|
+
BODY_TIME_SERIES_PERIODS = %w(1d 7d 30d 1w 1m 3m 6m 1y max)
|
7
|
+
|
8
|
+
# ======================================
|
9
|
+
# Boday Fat
|
10
|
+
# ======================================
|
11
|
+
|
12
|
+
# retrieves a list of all user's body fat log entries
|
13
|
+
# note: provide either end_date or period
|
14
|
+
# @param start_date start date for the logs
|
15
|
+
# @param end_date (optional)end date for the logs
|
16
|
+
# @param period (optional) period for the logs
|
17
|
+
def body_fat_logs(start_date: nil, end_date: nil, period: nil)
|
18
|
+
unless start_date
|
19
|
+
raise FitgemOauth2::InvalidArgumentError, 'must specify start_date'
|
20
|
+
end
|
21
|
+
url = ['user', user_id, 'body/log/fat/date', format_date(start_date)].join('/')
|
22
|
+
if end_date
|
23
|
+
url = [url, format_date(end_date)].join('/')
|
24
|
+
end
|
25
|
+
|
26
|
+
if period
|
27
|
+
if FAT_PERIODS.include?(period)
|
28
|
+
url = [url, period].join('/')
|
29
|
+
else
|
30
|
+
raise FitgemOauth2::InvalidArgumentError, "period must be one in #{FAT_PERIODS}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
url = url + '.json'
|
35
|
+
|
36
|
+
get_call(url)
|
37
|
+
end
|
38
|
+
|
39
|
+
# logs body fat
|
40
|
+
# @param params POST parameters for logging body fat
|
41
|
+
def log_body_fat(params)
|
42
|
+
post_call("user/#{user_id}/body/log/fat.json", params)
|
43
|
+
end
|
44
|
+
|
45
|
+
# delete logged body fat
|
46
|
+
# @param id ID of the log to be deleted.
|
47
|
+
def delete_logged_body_fat(id)
|
48
|
+
delete_call("user/#{user_id}/body/log/fat/#{id}.json")
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# ==================================
|
53
|
+
# Body Time Series
|
54
|
+
# ==================================
|
55
|
+
|
56
|
+
# retrieve body time series for the user; provide at least one of end_date and period
|
57
|
+
# @param resource (required)the resource requested ['bmi', 'fat', or 'weight']
|
58
|
+
# @param start_date (required)the start date for the series
|
59
|
+
# @param end_date (optional)the end date for the series
|
60
|
+
# @param period (optional)period for the time series. valid periods are BODY_TIME_SERIES_PERIODS
|
61
|
+
def body_time_series(resource: nil, start_date: nil, end_date: nil, period: nil)
|
62
|
+
unless resource && start_date
|
63
|
+
raise FitgemOauth2::InvalidArgumentError, 'resource and start_date are required parameters. Please specify both.'
|
64
|
+
end
|
65
|
+
|
66
|
+
url = ['user', user_id, 'body', resource, 'date', format_date(start_date)].join('/')
|
67
|
+
|
68
|
+
second = ''
|
69
|
+
if end_date && period
|
70
|
+
raise FitgemOauth2::InvalidArgumentError, 'Please specify either period or end date, not both.'
|
71
|
+
end
|
72
|
+
|
73
|
+
if period
|
74
|
+
if BODY_TIME_SERIES_PERIODS.include?(period)
|
75
|
+
second = period
|
76
|
+
else
|
77
|
+
raise FitgemOauth2::InvalidArgumentError, "Invalid Period. Body time series period must be in #{BODY_TIME_SERIES_PERIODS}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if end_date
|
82
|
+
second = format_date(end_date)
|
83
|
+
end
|
84
|
+
|
85
|
+
url = [url, second].join('/')
|
86
|
+
|
87
|
+
get_call(url + '.json')
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# ======================================
|
92
|
+
# Body Goals
|
93
|
+
# ======================================
|
94
|
+
|
95
|
+
# retrieves body goals based on the type specified
|
96
|
+
# @param type 'fat' or 'weight'
|
97
|
+
def body_goals(type)
|
98
|
+
if type && BODY_GOALS.include?(type)
|
99
|
+
get_call("user/#{user_id}/body/log/#{type}/goal.json")
|
100
|
+
else
|
101
|
+
raise FitgemOauth2::InvalidArgumentError, "invalid goal type : #{type}. must be one of #{BODY_GOALS}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# update body fat goal
|
106
|
+
# @param params POST params for updating body fat goal
|
107
|
+
def update_body_fat_goal(params)
|
108
|
+
post_call("user/#{user_id}/body/log/fat/goal.json", params)
|
109
|
+
end
|
110
|
+
|
111
|
+
# update weight goal
|
112
|
+
# @param params POST params for updating weight goal
|
113
|
+
def update_weight_goal(params)
|
114
|
+
post_call("user/#{user_id}/body/log/weight/goal.json", params)
|
115
|
+
end
|
116
|
+
|
117
|
+
# ======================================
|
118
|
+
# Body Weight
|
119
|
+
# ======================================
|
120
|
+
|
121
|
+
# retrieve weight logs; specify either the end_date or period
|
122
|
+
# @param start_date start date for the logs
|
123
|
+
# @param end_date (optional)end_date for the logs
|
124
|
+
# @param period (optional)period for the logs
|
125
|
+
def weight_logs(start_date: nil, end_date: nil, period: nil)
|
126
|
+
unless start_date
|
127
|
+
raise FitgemOauth2::InvalidArgumentError, 'start_date not specified.'
|
128
|
+
end
|
129
|
+
|
130
|
+
if period && end_date
|
131
|
+
raise FitgemOauth2::InvalidArgumentError, 'both end_date and period specified. please provide only one.'
|
132
|
+
end
|
133
|
+
|
134
|
+
if period
|
135
|
+
unless WEIGHT_PERIODS.include?(period)
|
136
|
+
raise FitgemOauth2::InvalidArgumentError, "valid period not specified. please choose a period from #{WEIGHT_PERIODS}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
first = format_date(start_date)
|
141
|
+
url = ['user', user_id, 'body/log/weight/date', first].join('/')
|
142
|
+
if period || end_date
|
143
|
+
second = period || format_date(end_date)
|
144
|
+
url = [url, second].join('/')
|
145
|
+
end
|
146
|
+
|
147
|
+
get_call(url + '.json')
|
148
|
+
end
|
149
|
+
|
150
|
+
# logs weight for the user
|
151
|
+
# @param params POST message for logging weight
|
152
|
+
def log_weight(params)
|
153
|
+
post_call("user/#{user_id}/body/log/weight.json", params)
|
154
|
+
end
|
155
|
+
|
156
|
+
# delete logged weight
|
157
|
+
# @param id ID of the weight log to be deleted
|
158
|
+
def delete_logged_weight(id)
|
159
|
+
delete_call("user/#{user_id}/body/log/weight/#{id}.json")
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
data/lib/fitgem_oauth2/client.rb
CHANGED
@@ -1,126 +1,126 @@
|
|
1
|
-
require 'fitgem_oauth2/activity.rb'
|
2
|
-
require 'fitgem_oauth2/body_measurements.rb'
|
3
|
-
require 'fitgem_oauth2/devices.rb'
|
4
|
-
require 'fitgem_oauth2/errors.rb'
|
5
|
-
require 'fitgem_oauth2/food.rb'
|
6
|
-
require 'fitgem_oauth2/friends.rb'
|
7
|
-
require 'fitgem_oauth2/heartrate.rb'
|
8
|
-
require 'fitgem_oauth2/sleep.rb'
|
9
|
-
require 'fitgem_oauth2/subscriptions.rb'
|
10
|
-
require 'fitgem_oauth2/users.rb'
|
11
|
-
require 'fitgem_oauth2/utils.rb'
|
12
|
-
require 'fitgem_oauth2/version.rb'
|
13
|
-
|
14
|
-
require 'base64'
|
15
|
-
require 'faraday'
|
16
|
-
|
17
|
-
module FitgemOauth2
|
18
|
-
class Client
|
19
|
-
|
20
|
-
DEFAULT_USER_ID = '-'
|
21
|
-
API_VERSION = '1'
|
22
|
-
|
23
|
-
attr_reader :client_id
|
24
|
-
attr_reader :client_secret
|
25
|
-
attr_reader :token
|
26
|
-
attr_reader :user_id
|
27
|
-
attr_reader :unit_system
|
28
|
-
|
29
|
-
def initialize(opts)
|
30
|
-
missing = [:client_id, :client_secret, :token] - opts.keys
|
31
|
-
if missing.size > 0
|
32
|
-
raise FitgemOauth2::InvalidArgumentError, "Missing required options: #{missing.join(',')}"
|
33
|
-
end
|
34
|
-
|
35
|
-
@client_id = opts[:client_id]
|
36
|
-
@client_secret = opts[:client_secret]
|
37
|
-
@token = opts[:token]
|
38
|
-
@user_id = (opts[:user_id] || DEFAULT_USER_ID)
|
39
|
-
@unit_system = opts[:unit_system]
|
40
|
-
@connection = Faraday.new('https://api.fitbit.com')
|
41
|
-
end
|
42
|
-
|
43
|
-
def refresh_access_token(refresh_token)
|
44
|
-
response = connection.post('/oauth2/token') do |request|
|
45
|
-
encoded = Base64.strict_encode64("#{@client_id}:#{@client_secret}")
|
46
|
-
request.headers['Authorization'] = "Basic #{encoded}"
|
47
|
-
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
48
|
-
request.params['grant_type'] = 'refresh_token'
|
49
|
-
request.params['refresh_token'] = refresh_token
|
50
|
-
end
|
51
|
-
JSON.parse(response.body)
|
52
|
-
end
|
53
|
-
|
54
|
-
def get_call(url)
|
55
|
-
url = "#{API_VERSION}/#{url}"
|
56
|
-
response = connection.get(url) { |request| set_headers(request) }
|
57
|
-
parse_response(response)
|
58
|
-
end
|
59
|
-
|
60
|
-
# This method is a helper method (like get_call) for 1.2 version of the API_VERSION
|
61
|
-
# This method is needed because Fitbit API supports both versions as of current
|
62
|
-
# date (Nov 5, 2017)
|
63
|
-
def get_call_1_2(url)
|
64
|
-
url = "1.2/#{url}"
|
65
|
-
response = connection.get(url) {|request| set_headers(request)}
|
66
|
-
parse_response(response)
|
67
|
-
end
|
68
|
-
|
69
|
-
def post_call(url, params = {})
|
70
|
-
url = "#{API_VERSION}/#{url}"
|
71
|
-
response = connection.post(url, params) { |request| set_headers(request) }
|
72
|
-
parse_response(response)
|
73
|
-
end
|
74
|
-
|
75
|
-
def post_call_1_2(url, params = {})
|
76
|
-
url = "1.2/#{url}"
|
77
|
-
response = connection.post(url, params) { |request| set_headers(request) }
|
78
|
-
parse_response(response)
|
79
|
-
end
|
80
|
-
|
81
|
-
def delete_call(url)
|
82
|
-
url = "#{API_VERSION}/#{url}"
|
83
|
-
response = connection.delete(url) { |request| set_headers(request) }
|
84
|
-
parse_response(response)
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
attr_reader :connection
|
89
|
-
|
90
|
-
def set_headers(request)
|
91
|
-
request.headers['Authorization'] = "Bearer #{token}"
|
92
|
-
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
93
|
-
request.headers['Accept-Language'] = unit_system unless unit_system == nil
|
94
|
-
end
|
95
|
-
|
96
|
-
def parse_response(response)
|
97
|
-
headers_to_keep = %w(fitbit-rate-limit-limit fitbit-rate-limit-remaining fitbit-rate-limit-reset)
|
98
|
-
|
99
|
-
error_handler = {
|
100
|
-
200 => lambda {
|
101
|
-
body = JSON.parse(response.body)
|
102
|
-
body = {body: body} if body.is_a?(Array)
|
103
|
-
headers = response.headers.to_hash.keep_if { |k,v|
|
104
|
-
headers_to_keep.include? k
|
105
|
-
}
|
106
|
-
body.merge!(headers)
|
107
|
-
},
|
108
|
-
201 => lambda { },
|
109
|
-
204 => lambda { },
|
110
|
-
400 => lambda { raise FitgemOauth2::BadRequestError },
|
111
|
-
401 => lambda { raise FitgemOauth2::UnauthorizedError },
|
112
|
-
403 => lambda { raise FitgemOauth2::ForbiddenError },
|
113
|
-
404 => lambda { raise FitgemOauth2::NotFoundError },
|
114
|
-
429 => lambda { raise FitgemOauth2::ApiLimitError },
|
115
|
-
500..599 => lambda { raise FitgemOauth2::ServerError }
|
116
|
-
}
|
117
|
-
|
118
|
-
fn = error_handler.detect { |k, _| k === response.status }
|
119
|
-
if fn === nil
|
120
|
-
raise StandardError, "Unexpected response status #{response.status}"
|
121
|
-
else
|
122
|
-
fn.last.call
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
1
|
+
require 'fitgem_oauth2/activity.rb'
|
2
|
+
require 'fitgem_oauth2/body_measurements.rb'
|
3
|
+
require 'fitgem_oauth2/devices.rb'
|
4
|
+
require 'fitgem_oauth2/errors.rb'
|
5
|
+
require 'fitgem_oauth2/food.rb'
|
6
|
+
require 'fitgem_oauth2/friends.rb'
|
7
|
+
require 'fitgem_oauth2/heartrate.rb'
|
8
|
+
require 'fitgem_oauth2/sleep.rb'
|
9
|
+
require 'fitgem_oauth2/subscriptions.rb'
|
10
|
+
require 'fitgem_oauth2/users.rb'
|
11
|
+
require 'fitgem_oauth2/utils.rb'
|
12
|
+
require 'fitgem_oauth2/version.rb'
|
13
|
+
|
14
|
+
require 'base64'
|
15
|
+
require 'faraday'
|
16
|
+
|
17
|
+
module FitgemOauth2
|
18
|
+
class Client
|
19
|
+
|
20
|
+
DEFAULT_USER_ID = '-'
|
21
|
+
API_VERSION = '1'
|
22
|
+
|
23
|
+
attr_reader :client_id
|
24
|
+
attr_reader :client_secret
|
25
|
+
attr_reader :token
|
26
|
+
attr_reader :user_id
|
27
|
+
attr_reader :unit_system
|
28
|
+
|
29
|
+
def initialize(opts)
|
30
|
+
missing = [:client_id, :client_secret, :token] - opts.keys
|
31
|
+
if missing.size > 0
|
32
|
+
raise FitgemOauth2::InvalidArgumentError, "Missing required options: #{missing.join(',')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
@client_id = opts[:client_id]
|
36
|
+
@client_secret = opts[:client_secret]
|
37
|
+
@token = opts[:token]
|
38
|
+
@user_id = (opts[:user_id] || DEFAULT_USER_ID)
|
39
|
+
@unit_system = opts[:unit_system]
|
40
|
+
@connection = Faraday.new('https://api.fitbit.com')
|
41
|
+
end
|
42
|
+
|
43
|
+
def refresh_access_token(refresh_token)
|
44
|
+
response = connection.post('/oauth2/token') do |request|
|
45
|
+
encoded = Base64.strict_encode64("#{@client_id}:#{@client_secret}")
|
46
|
+
request.headers['Authorization'] = "Basic #{encoded}"
|
47
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
48
|
+
request.params['grant_type'] = 'refresh_token'
|
49
|
+
request.params['refresh_token'] = refresh_token
|
50
|
+
end
|
51
|
+
JSON.parse(response.body)
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_call(url)
|
55
|
+
url = "#{API_VERSION}/#{url}"
|
56
|
+
response = connection.get(url) { |request| set_headers(request) }
|
57
|
+
parse_response(response)
|
58
|
+
end
|
59
|
+
|
60
|
+
# This method is a helper method (like get_call) for 1.2 version of the API_VERSION
|
61
|
+
# This method is needed because Fitbit API supports both versions as of current
|
62
|
+
# date (Nov 5, 2017)
|
63
|
+
def get_call_1_2(url)
|
64
|
+
url = "1.2/#{url}"
|
65
|
+
response = connection.get(url) {|request| set_headers(request)}
|
66
|
+
parse_response(response)
|
67
|
+
end
|
68
|
+
|
69
|
+
def post_call(url, params = {})
|
70
|
+
url = "#{API_VERSION}/#{url}"
|
71
|
+
response = connection.post(url, params) { |request| set_headers(request) }
|
72
|
+
parse_response(response)
|
73
|
+
end
|
74
|
+
|
75
|
+
def post_call_1_2(url, params = {})
|
76
|
+
url = "1.2/#{url}"
|
77
|
+
response = connection.post(url, params) { |request| set_headers(request) }
|
78
|
+
parse_response(response)
|
79
|
+
end
|
80
|
+
|
81
|
+
def delete_call(url)
|
82
|
+
url = "#{API_VERSION}/#{url}"
|
83
|
+
response = connection.delete(url) { |request| set_headers(request) }
|
84
|
+
parse_response(response)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
attr_reader :connection
|
89
|
+
|
90
|
+
def set_headers(request)
|
91
|
+
request.headers['Authorization'] = "Bearer #{token}"
|
92
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
93
|
+
request.headers['Accept-Language'] = unit_system unless unit_system == nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_response(response)
|
97
|
+
headers_to_keep = %w(fitbit-rate-limit-limit fitbit-rate-limit-remaining fitbit-rate-limit-reset)
|
98
|
+
|
99
|
+
error_handler = {
|
100
|
+
200 => lambda {
|
101
|
+
body = JSON.parse(response.body)
|
102
|
+
body = {body: body} if body.is_a?(Array)
|
103
|
+
headers = response.headers.to_hash.keep_if { |k,v|
|
104
|
+
headers_to_keep.include? k
|
105
|
+
}
|
106
|
+
body.merge!(headers)
|
107
|
+
},
|
108
|
+
201 => lambda { },
|
109
|
+
204 => lambda { },
|
110
|
+
400 => lambda { raise FitgemOauth2::BadRequestError },
|
111
|
+
401 => lambda { raise FitgemOauth2::UnauthorizedError },
|
112
|
+
403 => lambda { raise FitgemOauth2::ForbiddenError },
|
113
|
+
404 => lambda { raise FitgemOauth2::NotFoundError },
|
114
|
+
429 => lambda { raise FitgemOauth2::ApiLimitError },
|
115
|
+
500..599 => lambda { raise FitgemOauth2::ServerError }
|
116
|
+
}
|
117
|
+
|
118
|
+
fn = error_handler.detect { |k, _| k === response.status }
|
119
|
+
if fn === nil
|
120
|
+
raise StandardError, "Unexpected response status #{response.status}"
|
121
|
+
else
|
122
|
+
fn.last.call
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|