vainglory-api 0.0.3 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: df230271ab484d16bf6be0704412c6c738adbc50
4
- data.tar.gz: 4e8f5f358709b76ceb99f394cd0d5d1d40a8dad9
3
+ metadata.gz: 77529bebc4c054437e5568b468cab881c10e4c45
4
+ data.tar.gz: 0e605b5f0f1291c6b5ad72b5883c1b2a60087605
5
5
  SHA512:
6
- metadata.gz: 98837caf5b1f58a0ec473f87585b972863048079ae6ffb00e7d83ac7dd937b37ae297ff4d8004c194fe73e7b9e6e160170f75261b2be8cc5898c2229d8f9e294
7
- data.tar.gz: 3dfcf7e3aa98c1f9392c9900de72d10ee704c76d1c2564c7e7042013217a0f407406f166d7a50d00c689c415af6b0125397415a46a29528952fde455e3a9e205
6
+ metadata.gz: e3b5a08e3ee00f30e09f182b074a090f5944a74c863e8c0e0b38743394667f4d52b250216ab0f4f6d8e0bc5d463cd02a533486c86efeba5cbd3592955fd6da38
7
+ data.tar.gz: dd326e89fe122bbdaa7fe6cb92c5e7c29cdd49e4a64d5914b7b31f74b766b7e4f823824971009a4c832732d60f9fa8eb630f6b7559a9cafaf8c1289d2b4d032a
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ Gemfile.lock
46
+ .ruby-version
47
+ .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ # .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,2 @@
1
+ Documentation:
2
+ Enabled: false
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4.0
4
+ - 2.3.3
5
+ - 2.2
6
+ - 2.1
7
+ - 2.0
8
+ sudo: false
9
+ gemfile: Gemfile
10
+ script: bundle exec rspec spec
11
+ addons:
12
+ code_climate:
13
+ repo_token: d20c1b4862616550a65962ceecf0299c70a844cbce54a230b5234804ac2725dc
14
+ after_success:
15
+ - bundle exec codeclimate-test-reporter
@@ -0,0 +1,6 @@
1
+ ### 0.0.3 - 2017-03-28
2
+ - Ruby version >= 2.0 is required
3
+
4
+ ### 0.0.2 - 2017-03-28
5
+
6
+ ### 0.0.1 - 2017-03-28
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Chet Bortz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,112 @@
1
+ # vainglory-api
2
+ [![Gem Version](https://badge.fury.io/rb/vainglory-api.svg)](https://badge.fury.io/rb/vainglory-api)
3
+ [![Travis CI](https://travis-ci.org/cbortz/vainglory-api-ruby.svg?branch=master)](https://travis-ci.org/cbortz/vainglory-api-ruby)
4
+ [![Code Climate](https://codeclimate.com/github/cbortz/vainglory-api-ruby/badges/gpa.svg)](https://codeclimate.com/github/cbortz/vainglory-api-ruby)
5
+ [![Test Coverage](https://codeclimate.com/github/cbortz/vainglory-api-ruby/badges/coverage.svg)](https://codeclimate.com/github/cbortz/vainglory-api-ruby/coverage)
6
+ [![Inline docs](http://inch-ci.org/github/cbortz/vainglory-api-ruby.svg?branch=master)](http://inch-ci.org/github/cbortz/vainglory-api-ruby)
7
+
8
+ - [YARD Documentation](http://www.rubydoc.info/github/cbortz/vainglory-api-ruby)
9
+ - [Official Vainglory API Documentation](https://developer.vainglorygame.com/docs)
10
+
11
+ ---
12
+
13
+ ## Getting Started
14
+
15
+ VaingloryAPI works with Ruby 2.0 onwards. Please refer to the [YARD Documentation](http://www.rubydoc.info/github/cbortz/vainglory-api-ruby) for a better understanding of how everything works.
16
+
17
+ ### Installation
18
+
19
+ You can add it to your Gemfile with:
20
+
21
+ ```ruby
22
+ gem 'vainglory-api'
23
+ ```
24
+
25
+ Then run `bundle install`
26
+
27
+ You can also install it manually with:
28
+
29
+ ```bash
30
+ gem install vainglory-api
31
+ ```
32
+
33
+ ### Usage
34
+
35
+ You can create an instance of the API client by initializing with your API key and [specified region](https://developer.vainglorygame.com/docs#regions) (`na` is the default):
36
+
37
+ ```ruby
38
+ client = VaingloryAPI.new('YOUR_API_KEY', 'na')
39
+ ```
40
+
41
+ #### Helper Attributes
42
+
43
+ All client methods return an `OpenStruct` object containing the response attributes with some additional helper attributes.
44
+
45
+ ```ruby
46
+ response = client.samples
47
+
48
+ response.code # The HTTP response code
49
+ response.success? # Returns true if the response code is less than 300
50
+ response.raw # The complete HTTP response
51
+ ```
52
+
53
+ #### Rate Limits
54
+
55
+ Each request will return data about your rate limits.
56
+
57
+ ```ruby
58
+ response.rate_limit # Request limit per day / per minute
59
+ response.rate_remaining # The number of requests left for the time window
60
+ response.rate_reset # The remaining window before the rate limit is refilled in UTC epoch nanoseconds.
61
+ ```
62
+
63
+ More information: https://developer.vainglorygame.com/docs#rate-limits
64
+
65
+ #### Filtering
66
+
67
+ Currently, filters are supported by these client methods:
68
+
69
+ - `VaingloryAPI::Client#matches`
70
+ - `VaingloryAPI::Client#samples`
71
+
72
+ You can pass filters in as a hash using the exact Query Parameter key names outlined in the [Vainglory API Documentation](https://developer.vainglorygame.com/docs).
73
+
74
+ ```ruby
75
+ # Example matches request with filter
76
+ client.matches('filter[playerNames]' => 'boombastic04,IHaveNoIdea')
77
+ ```
78
+
79
+ #### Methods
80
+
81
+ To get __multiple matches__:
82
+
83
+ ```ruby
84
+ client.matches
85
+ ```
86
+
87
+ To get __single match data__, you must provide the ID of a match:
88
+
89
+ ```ruby
90
+ client.match('37f94e56-1360-11e7-a250-062445d3d668')
91
+ ```
92
+
93
+ You can search for data of __one or more players__ by passing their in-game names (IGNs):
94
+
95
+ ```ruby
96
+ client.players('boombastic04', 'IHaveNoIdea')
97
+ ```
98
+
99
+ To get data about a __single player__, you must provide the ID of the player:
100
+
101
+ ```ruby
102
+ client.player('6abb30de-7cb8-11e4-8bd3-06eb725f8a76')
103
+ ```
104
+
105
+ To get __Telemetry__ data, you must provide the data URL:
106
+
107
+ ```ruby
108
+ client.telemetry('https://gl-prod-us-east-1.s3.amazonaws.com/assets/semc-vainglory/na/2017/03/28/03/07/b0bb7faf-1363-11e7-b11e-0242ac110006-telemetry.json')
109
+ ```
110
+
111
+ ## License
112
+ [MIT License](LICENSE). Copyright 2017 Chet Bortz
@@ -1,110 +1,21 @@
1
- require 'json'
2
- require 'ostruct'
3
- require 'openssl'
4
- require 'net/http'
5
-
6
- class VaingloryAPI
7
- BASE_URL = "https://api.dc01.gamelockerapp.com"
8
-
9
- def initialize(api_key, region = "na")
10
- @api_key = api_key
11
- @region = region
12
- end
13
-
14
- def samples(filter_params = {})
15
- get_request(endpoint_uri("shards/#{@region}/samples", filter_params))
16
- end
17
-
18
- def matches(filter_params = {})
19
- get_request(endpoint_uri("shards/#{@region}/matches", filter_params))
20
- end
21
-
22
- def match(match_id)
23
- get_request(endpoint_uri("shards/#{@region}/matches/#{match_id}"))
24
- end
25
-
26
- def players(*names)
27
- filter_params = {"filter[playerNames]" => names.join(',')}
28
- get_request(endpoint_uri("shards/#{@region}/players", filter_params))
29
- end
30
-
31
- def player(player_id)
32
- get_request(endpoint_uri("shards/#{@region}/players/#{player_id}"))
33
- end
34
-
35
- def telemetry(url)
36
- get_request(URI(url), true, false)
37
- end
38
-
39
- def teams(filter_params = {})
40
- raise(NotImplementedError, "Coming soon!")
41
- end
42
-
43
- def team(team_id)
44
- raise(NotImplementedError, "Coming soon!")
45
- end
46
-
47
- def link(link_id)
48
- raise(NotImplementedError, "Coming soon!")
49
- end
50
-
51
- def status
52
- get_request_without_headers(endpoint_uri('status'))
53
- end
54
-
55
- private
56
-
57
- def get_request_without_headers(uri)
58
- get_request(uri, false)
59
- end
60
-
61
- def get_request(uri, with_headers = true, with_auth = true)
62
- req = Net::HTTP::Get.new(uri)
63
- req = apply_headers(req, with_auth) if with_headers
64
-
65
- request(uri, req)
66
- end
67
-
68
- def apply_headers(req, with_auth = true)
69
- req['Authorization'] = "Bearer #{@api_key}" if with_auth
70
- req['X-TITLE-ID'] = "semc-vainglory"
71
- req['Accept'] = "application/vnd.api+json"
72
-
73
- req
74
- end
75
-
76
- def request(uri, req)
77
- http = Net::HTTP.new(uri.host, uri.port)
78
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
79
- http.use_ssl = true
80
-
81
- response(http.request(req))
82
- end
83
-
84
- def endpoint_uri(path, filter_params = {})
85
- uri = URI(endpoint_url(path))
86
- uri.query = URI.encode_www_form(filter_params)
87
-
88
- uri
89
- end
90
-
91
- def endpoint_url(path)
92
- [BASE_URL, path].join('/')
93
- end
94
-
95
- def response(response_data)
96
- parsed_body = JSON.parse(response_data.body, object_class: OpenStruct)
97
- parsed_code = response_data.code.to_i
98
-
99
- OpenStruct.new({
100
- code: parsed_code,
101
- success?: parsed_code < 300,
102
- rate_limit: response_data['X-RateLimit-Limit'].to_i,
103
- rate_remaining: response_data['X-RateLimit-Remaining'].to_i,
104
- rate_reset: response_data['X-RateLimit-Reset'].to_i,
105
- data: parsed_body.respond_to?(:data) ? parsed_body.data : parsed_body,
106
- error: parsed_body.respond_to?(:error)? parsed_body.error : nil,
107
- raw: response_data
108
- })
109
- end
1
+ require 'vainglory_api/client'
2
+
3
+ # A Ruby libary wrapper for the Vainglory API
4
+ #
5
+ # @author Chet Bortz
6
+ module VaingloryAPI
7
+ # Alias for VaingloryAPI::Client constructor
8
+ #
9
+ # @overload new(api_key, region)
10
+ # @param api_key (String) your Vainglory API key
11
+ # @param region (String) the short name for your specified Region shard
12
+ # @param (see VaingloryAPI::Client#initialize)
13
+ # @example Initialize a new client
14
+ # client = VaingloryAPI.new('API_KEY', 'na')
15
+ # @return [VaingloryAPI::Client] an instance of the client
16
+ # @see VaingloryAPI::Client#initialize
17
+ def new(*args)
18
+ Client.new(*args)
19
+ end
20
+ module_function :new
110
21
  end
@@ -0,0 +1,244 @@
1
+ require 'json'
2
+ require 'ostruct'
3
+ require 'openssl'
4
+ require 'net/http'
5
+
6
+ module VaingloryAPI
7
+ # Used to interface with the official Vainglory API
8
+ #
9
+ # @see https://developer.vainglorygame.com/docs Vainglory API Documentation
10
+ # @see https://developer.vainglorygame.com/docs#payload Vainglory API "Payload"
11
+ # @see https://developer.vainglorygame.com/docs#rate-limits Vainglory API "Rate Limits"
12
+ class Client
13
+ # The base URL used for most requests
14
+ BASE_URL = 'https://api.dc01.gamelockerapp.com'.freeze
15
+
16
+ # A new instance of Client.
17
+ #
18
+ # @param (String) api_key your Vainglory API key
19
+ # @param (String) region the short name for your specified Region shard
20
+ # @example Initialize a new client
21
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
22
+ # @return [Client] a new instance of the client
23
+ def initialize(api_key, region = 'na')
24
+ @api_key = api_key
25
+ @region = region
26
+ end
27
+
28
+ # Gets batches of random match data
29
+ #
30
+ # @param [Hash] filter_params the parameters used to filter results
31
+ # @option filter_params [String] 'page[offset]' (0) Allows paging over results
32
+ # @option filter_params [String] 'page[limit]' (50) Values less than 50 and great than 2 are supported.
33
+ # @option filter_params [String] 'sort' (createdAt) By default, Matches are sorted by creation time ascending.
34
+ # @option filter_params [String] 'filter[createdAt-start]' (3hrs ago) Must occur before end time. Format is iso8601
35
+ # @option filter_params [String] 'filter[createdAt-end]' (Now) Queries search the last 3 hrs. Format is iso8601
36
+ # @example Get samples
37
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
38
+ # client.samples
39
+ # @return [OpenStruct] the response and metadata
40
+ # @see https://developer.vainglorygame.com/docs#samples Vainglory API "Samples"
41
+ # @see https://developer.vainglorygame.com/docs#pagination Vainglory API "Pagination"
42
+ # @see https://developer.vainglorygame.com/docs#sorting Vainglory API "Sorting"
43
+ def samples(filter_params = {})
44
+ get_request(endpoint_uri("shards/#{@region}/samples", filter_params))
45
+ end
46
+
47
+ # Gets data from matches (multiple)
48
+ #
49
+ # @param [Hash] filter_params the parameters used to filter results
50
+ # @option filter_params [String] 'page[offset]' (0) Allows paging over results
51
+ # @option filter_params [String] 'page[limit]' (50) Values less than 50 and great than 2 are supported.
52
+ # @option filter_params [String] 'sort' (createdAt) By default, Matches are sorted by creation time ascending.
53
+ # @option filter_params [String] 'filter[createdAt-start]' (3hrs ago) Must occur before end time. Format is iso8601
54
+ # @option filter_params [String] 'filter[createdAt-end]' (Now) Queries search the last 3 hrs. Format is iso8601
55
+ # @option filter_params [String] 'filter[playerNames]' Filters by player name, separated by commas.
56
+ # @option filter_params [String] 'filter[playerIds]' Filters by player Id, separated by commas.
57
+ # @option filter_params [String] 'filter[teamNames]' Filters by team names. Team names are the same as the in game team tags.
58
+ # @option filter_params [String] 'filter[gameMode]' Filters by Game Mode
59
+ # @example Get matches
60
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
61
+ # client.matches
62
+ # @example Get matches with a filter
63
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
64
+ # client.matches('filter[playerNames]' => 'player_name')
65
+ # @return [OpenStruct] the response and metadata
66
+ # @see https://developer.vainglorygame.com/docs#get-a-collection-of-matches Vainglory API "Get a collection of Matches"
67
+ # @see https://developer.vainglorygame.com/docs#rosters Vainglory API "Rosters"
68
+ # @see https://developer.vainglorygame.com/docs#match-data-summary Vainglory API "Match Data Summary"
69
+ # @see https://developer.vainglorygame.com/docs#pagination Vainglory API "Pagination"
70
+ # @see https://developer.vainglorygame.com/docs#sorting Vainglory API "Sorting"
71
+ def matches(filter_params = {})
72
+ get_request(endpoint_uri("shards/#{@region}/matches", filter_params))
73
+ end
74
+
75
+ # Gets data for a single match
76
+ # @param [String] match_id the ID of the requested match
77
+ # @example Get a single match
78
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
79
+ # client.match('MATCH_ID')
80
+ #
81
+ # @return [OpenStruct] the response and metadata
82
+ # @see https://developer.vainglorygame.com/docs#get-a-single-match Vainglory API "Get a single Match"
83
+ # @see https://developer.vainglorygame.com/docs#rosters Vainglory API "Rosters"
84
+ # @see https://developer.vainglorygame.com/docs#match-data-summary Vainglory API "Match Data Summary"
85
+ def match(match_id)
86
+ get_request(endpoint_uri("shards/#{@region}/matches/#{match_id}"))
87
+ end
88
+
89
+ # Gets data about players (one or more)
90
+ #
91
+ # @param [String] player_name the in-game name (IGN) of a player
92
+ # @param [String] additional_player_names additional IGNs for search for
93
+ # @example Search for a player
94
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
95
+ # client.players('player_name')
96
+ # @example Search for multiple players
97
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
98
+ # client.players('player_name', 'player_name2')
99
+ # @return [OpenStruct] the response and metadata
100
+ # @see https://developer.vainglorygame.com/docs#get-a-collection-of-players Vainglory API "Get a collection of players"
101
+ def players(player_name, *additional_player_names)
102
+ player_names = [player_name].concat(additional_player_names)
103
+ filter_params = { 'filter[playerNames]' => player_names.join(',') }
104
+ get_request(endpoint_uri("shards/#{@region}/players", filter_params))
105
+ end
106
+
107
+ # Gets data for a single player
108
+ #
109
+ # @param [String] player_id the ID of the requested player
110
+ # @example Get a single player
111
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
112
+ # client.match('PLAYER_ID')
113
+ # @return [OpenStruct] the response and metadata
114
+ # @see https://developer.vainglorygame.com/docs#get-a-single-player Vainglory API "Get a single Player"
115
+ def player(player_id)
116
+ get_request(endpoint_uri("shards/#{@region}/players/#{player_id}"))
117
+ end
118
+
119
+ # Gets telemtry data from a specified URL
120
+ #
121
+ # @param [String] url the URL of the requested Telemetry data
122
+ # @example Get telemetry data
123
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
124
+ # client.telemetry('TELEMETRY_URL')
125
+ # @return [OpenStruct] the response and metadata
126
+ # @see https://developer.vainglorygame.com/docs#telemetry Vainglory API "Telemetry"
127
+ def telemetry(url)
128
+ get_request(URI(url), true, false)
129
+ end
130
+
131
+ # Gets aggregated lifetime information about teams (multiple)
132
+ #
133
+ # @param [Hash] _filter_params the parameters used to filter results
134
+ # @option _filter_params [String] 'filter[teamNames]' Filters by team name
135
+ # @option _filter_params [String] 'filter[teamIds]' Filters by team ID
136
+ # @raise [NotImplementedError] this endpoint is not yet available
137
+ # @see https://developer.vainglorygame.com/docs#teams-coming-soon Vainglory API "Get a collection of Teams"
138
+ def teams(_filter_params = {})
139
+ raise(NotImplementedError, 'Coming soon!')
140
+ end
141
+
142
+ # Gets aggregated lifetime information about a single team
143
+ #
144
+ # @raise [NotImplementedError] this endpoint is not yet available
145
+ # @see https://developer.vainglorygame.com/docs#get-a-single-team Vainglory API "Get a single Team"
146
+ def team(_team_id)
147
+ raise(NotImplementedError, 'Coming soon!')
148
+ end
149
+
150
+ # Checks to see if a link object exists for a given code
151
+ #
152
+ # @raise [NotImplementedError] this endpoint is not yet available
153
+ # @see https://developer.vainglorygame.com/docs#links-coming-soon Vainglory API "Links"
154
+ def link(_link_id)
155
+ raise(NotImplementedError, 'Coming soon!')
156
+ end
157
+
158
+ # Gets current API version and release date
159
+ #
160
+ # @example Get the API's status information
161
+ # client = VaingloryAPI::Client.new('API_KEY', 'na')
162
+ # client.status
163
+ # @return [OpenStruct] the response and metadata
164
+ # @see https://developer.vainglorygame.com/docs#versioning Vainglory API "Versioning"
165
+ def status
166
+ get_request_without_headers(endpoint_uri('status'))
167
+ end
168
+
169
+ private
170
+
171
+ def get_request_without_headers(uri)
172
+ get_request(uri, false)
173
+ end
174
+
175
+ def get_request(uri, with_headers = true, with_auth = true)
176
+ req = Net::HTTP::Get.new(uri)
177
+ req = apply_headers(req, with_auth) if with_headers
178
+
179
+ request(uri, req)
180
+ end
181
+
182
+ def apply_headers(req, with_auth = true)
183
+ req['Authorization'] = "Bearer #{@api_key}" if with_auth
184
+ req['X-TITLE-ID'] = 'semc-vainglory'
185
+ req['Accept'] = 'application/vnd.api+json'
186
+
187
+ req
188
+ end
189
+
190
+ def request(uri, req)
191
+ http = Net::HTTP.new(uri.host, uri.port)
192
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
193
+ http.use_ssl = true
194
+
195
+ response(http.request(req))
196
+ end
197
+
198
+ def endpoint_uri(path, filter_params = {})
199
+ uri = URI(endpoint_url(path))
200
+ uri.query = URI.encode_www_form(filter_params)
201
+
202
+ uri
203
+ end
204
+
205
+ def endpoint_url(path)
206
+ [BASE_URL, path].join('/')
207
+ end
208
+
209
+ def response(response_data)
210
+ response_object = serialize_response_data(response_data.body)
211
+ metadata = serialize_response_metadata(response_data)
212
+
213
+ # Add metadata members to response_object
214
+ metadata.each do |k, v|
215
+ response_object[k] = v
216
+ end
217
+
218
+ response_object
219
+ end
220
+
221
+ def serialize_response_metadata(response_data)
222
+ response_code = response_data.code.to_i
223
+
224
+ {
225
+ code: response_code,
226
+ success?: response_code < 300,
227
+ rate_limit: response_data['X-RateLimit-Limit'].to_i,
228
+ rate_remaining: response_data['X-RateLimit-Remaining'].to_i,
229
+ rate_reset: response_data['X-RateLimit-Reset'].to_i,
230
+ raw: response_data
231
+ }
232
+ end
233
+
234
+ def serialize_response_data(raw_response_body)
235
+ data = JSON.parse(raw_response_body, object_class: OpenStruct)
236
+
237
+ if data.is_a?(Array)
238
+ OpenStruct.new(data: data)
239
+ else
240
+ data
241
+ end
242
+ end
243
+ end
244
+ end