bubbles-rest-client 0.3.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ module Bubbles
10
10
  ##
11
11
  # Configure the Bubbles instance.
12
12
  #
13
- # Use this method if you want to configure the Bubbles instance, typically during intialization of your Gem or
13
+ # Use this method if you want to configure the Bubbles instance, typically during initialization of your Gem or
14
14
  # application.
15
15
  #
16
16
  # @example In app/config/initializers/bubbles.rb
@@ -39,42 +39,85 @@ module Bubbles
39
39
  #
40
40
  class Configuration
41
41
  def initialize
42
- @environment_scheme = 'http'
43
- @environment_host = '127.0.0.1'
44
- @environment_port = '1234'
45
- @environment_api_key = nil
46
-
42
+ @environments = Hash.new
47
43
  @endpoints = Hash.new
48
44
  end
49
45
 
50
46
  ##
51
- # Retrieve the {RestEnvironment} object defined as part of this Configuration.
47
+ # Retrieve the {RestEnvironment} object defined as part of this Configuration having a specified name.
48
+ #
49
+ # @param [String] environment_name The name of the {RestEnvironment} to retrieve.
50
+ #
51
+ # The +environment_name+ is +nil+ by default, which will return the default configuration, if only one exists.
52
52
  #
53
- # Note that this constructs a new +RestEnvironment+ and returns it, rather than returning an existing object.
53
+ # @return [RestEnvironment] A new +RestEnvironment+ having the configuration that was created with key
54
+ # +environment_name+. Note that +RestEnvironment+s are essentially immutable once they are created, so
55
+ # an existing object will _never_ be returned.
54
56
  #
55
- def environment
56
- RestEnvironment.new(@environment_scheme, @environment_host, @environment_port, @environment_api_key)
57
+ def environment(environment_name = nil)
58
+ if environment_name.nil?
59
+ if @environments.length > 1
60
+ raise 'You must specify an environment_name parameter because more than one environment is defined'
61
+ end
62
+
63
+ env_hash = @environments[nil]
64
+ else
65
+ env_hash = @environments[environment_name]
66
+ end
67
+
68
+ if env_hash.nil?
69
+ if environment_name.nil?
70
+ raise 'No default environment specified'
71
+ end
72
+
73
+ raise 'No environment specified having name {}', environment_name
74
+ end
75
+
76
+ RestEnvironment.new(env_hash[:scheme], env_hash[:host], env_hash[:port], env_hash[:api_key],
77
+ env_hash[:api_key_name])
57
78
  end
58
79
 
59
80
  ##
60
- # Set the current environment.
81
+ # Set the environments that can be used.
61
82
  #
62
- # @param [Object] env The environment, as a generic Ruby Object.
83
+ # @param [Array] environments The environments, as an array with each entry a +Hash+.
84
+ #
85
+ # One or more environments may be specified, but if more than one environment is specified, it is required that each
86
+ # environment have a +:environment_name:+ parameter to differentiate it from other environments.
63
87
  #
64
88
  # @example In app/config/environments/staging.rb:
65
89
  # Bubbles.configure do |config|
66
- # config.environment = {
90
+ # config.environments = [{
67
91
  # :scheme => 'https',
68
92
  # :host => 'stage.api.somehost.com',
69
- # :port => '443'
70
- # }
93
+ # :port => '443',
94
+ # :api_key => 'something',
95
+ # :api_key_name => 'X-API-Key' # Optional
96
+ # }]
71
97
  # end
72
98
  #
73
- def environment=(env)
74
- @environment_scheme = env[:scheme]
75
- @environment_host = env[:host]
76
- @environment_port = env[:port]
77
- @environment_api_key = env[:api_key]
99
+ def environments=(environments)
100
+ default = nil
101
+ environments.each do |environment|
102
+ if environments.length > 1 && environment[:environment_name].nil?
103
+ message = 'More than one environment was specified and at least one of the environments does not have an ' \
104
+ ':environment_name field. Verify all environments have an :environment_name.'
105
+
106
+ raise message
107
+ end
108
+
109
+ @environments = {}
110
+ env_api_key = 'X-API-Key'
111
+ env_api_key = environment[:api_key_name] if environment.key? :api_key_name
112
+
113
+ @environments[environment[:environment_name]] = {
114
+ scheme: environment[:scheme],
115
+ host: environment[:host],
116
+ port: environment[:port],
117
+ api_key: environment[:api_key],
118
+ api_key_name: env_api_key
119
+ }
120
+ end
78
121
  end
79
122
 
80
123
  ##
@@ -103,7 +146,7 @@ module Bubbles
103
146
  def endpoints=(endpoints)
104
147
  new_endpoints = Hash.new
105
148
  endpoints.each do |ep|
106
- endpoint_object = Endpoint.new ep[:method], ep[:location].to_s, ep[:authenticated], ep[:api_key_required], ep[:name], ep[:return_type], ep[:encode_authorization]
149
+ endpoint_object = Endpoint.new ep[:method], ep[:location].to_s, ep[:authenticated], ep[:api_key_required], ep[:name], ep[:return_type], ep[:encode_authorization], ep[:headers]
107
150
 
108
151
  new_endpoints[endpoint_object.get_key_string] = endpoint_object
109
152
  end
@@ -128,99 +171,113 @@ module Bubbles
128
171
  if endpoint.authenticated?
129
172
  Bubbles::RestEnvironment.class_exec do
130
173
  if endpoint.has_uri_params?
131
- define_method(endpoint_name_as_sym) do |auth_token, uri_params|
132
- RestClientResources.execute_get_authenticated self, endpoint, auth_token, uri_params
174
+ if endpoint.encode_authorization_header?
175
+ define_method(endpoint_name_as_sym) do |username, password, uri_params|
176
+ login_data = {
177
+ :login => username,
178
+ :password => password
179
+ }
180
+ auth_value = RestClientResources.get_encoded_authorization(endpoint, login_data)
181
+ RestClientResources.execute_get_authenticated self, endpoint, :basic, auth_value, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
182
+ end
183
+ else
184
+ define_method(endpoint_name_as_sym) do |auth_token, uri_params|
185
+ RestClientResources.execute_get_authenticated self, endpoint, :bearer, auth_token, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
186
+ end
133
187
  end
134
188
  else
135
- define_method(endpoint_name_as_sym) do |auth_token|
136
- RestClientResources.execute_get_authenticated self, endpoint, auth_token, {}
189
+ if endpoint.encode_authorization_header?
190
+ define_method(endpoint_name_as_sym) do |username, password|
191
+ login_data = {
192
+ :username => username,
193
+ :password => password
194
+ }
195
+ auth_value = RestClientResources.get_encoded_authorization(endpoint, login_data)
196
+
197
+ RestClientResources.execute_get_authenticated self, endpoint, :basic, auth_value, {}, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
198
+ end
199
+ else
200
+ define_method(endpoint_name_as_sym) do |auth_token|
201
+ RestClientResources.execute_get_authenticated self, endpoint, :bearer, auth_token, {}, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
202
+ end
137
203
  end
138
204
  end
139
205
  end
140
206
  else
141
207
  Bubbles::RestEnvironment.class_exec do
142
- define_method(endpoint_name_as_sym) do
143
- RestClientResources.execute_get_unauthenticated self, endpoint
208
+ if endpoint.has_uri_params?
209
+ define_method(endpoint_name_as_sym) do |uri_params|
210
+ RestClientResources.execute_get_unauthenticated self, endpoint, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
211
+ end
212
+ else
213
+ define_method(endpoint_name_as_sym) do
214
+ RestClientResources.execute_get_unauthenticated self, endpoint, {}, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
215
+ end
144
216
  end
145
217
  end
146
218
  end
147
219
  elsif endpoint.method == :post
148
- if endpoint.authenticated?
220
+ if endpoint.authenticated? and !endpoint.encode_authorization_header?
149
221
  Bubbles::RestEnvironment.class_exec do
150
222
  define_method(endpoint_name_as_sym) do |auth_token, data|
151
- RestClientResources.execute_post_authenticated self, endpoint, auth_token, data
223
+ RestClientResources.execute_post_authenticated self, endpoint, :bearer, auth_token, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
152
224
  end
153
225
  end
154
- else
155
- if endpoint.api_key_required?
156
- Bubbles::RestEnvironment.class_exec do
157
- define_method(endpoint_name_as_sym) do |data|
158
- additional_headers = {}
159
- if endpoint.encode_authorization_header?
160
- count = 0
161
- auth_value = ''
162
- endpoint.encode_authorization.each { |auth_key|
163
- if data[auth_key]
164
- if count > 0
165
- auth_value = auth_value + ':' + data[auth_key]
166
- else
167
- auth_value = data[auth_key]
168
- end
169
-
170
- count = count + 1
171
-
172
- data.delete(auth_key)
173
- end
174
- }
175
-
176
- additional_headers[:Authorization] = 'Basic ' + Base64.strict_encode64(auth_value)
177
- end
226
+ elsif endpoint.encode_authorization_header?
227
+ Bubbles::RestEnvironment.class_exec do
228
+ define_method(endpoint_name_as_sym) do |username, password, data = {}|
229
+ login_data = {
230
+ :username => username,
231
+ :password => password
232
+ }
178
233
 
179
- RestClientResources.execute_post_with_api_key self, endpoint, self.api_key, data, additional_headers
180
- end
234
+ auth_value = RestClientResources.get_encoded_authorization(endpoint, login_data)
235
+ # composite_headers = RestClientResources.build_composite_headers(endpoint.additional_headers, {
236
+ # Authorization: 'Basic ' + Base64.strict_encode64(auth_value)
237
+ # })
238
+ RestClientResources.execute_post_authenticated self, endpoint, :basic, auth_value, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
239
+ end
240
+ end
241
+ else
242
+ Bubbles::RestEnvironment.class_exec do
243
+ define_method(endpoint_name_as_sym) do |data|
244
+ composite_headers = endpoint.additional_headers
245
+ RestClientResources.execute_post_unauthenticated self, endpoint, data, composite_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
181
246
  end
182
- else
183
- raise 'Unauthenticated POST requests without an API key are not allowed'
184
247
  end
185
248
  end
186
249
  elsif endpoint.method == :delete
187
- if endpoint.authenticated?
188
- Bubbles::RestEnvironment.class_exec do
189
- if endpoint.has_uri_params?
250
+ if endpoint.has_uri_params?
251
+ if endpoint.authenticated?
252
+ Bubbles::RestEnvironment.class_exec do
190
253
  define_method(endpoint_name_as_sym) do |auth_token, uri_params|
191
- RestClientResources.execute_delete_authenticated self, endpoint, auth_token, uri_params
254
+ RestClientResources.execute_delete_authenticated self, endpoint, auth_token, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
255
+ end
256
+ end
257
+ else
258
+ Bubbles::RestEnvironment.class_exec do
259
+ define_method(endpoint_name_as_sym) do |uri_params|
260
+ RestClientResources.execute_delete_unauthenticated self, endpoint, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
192
261
  end
193
- else
194
- # NOTE: While MDN states that DELETE requests with a body are allowed, it seems that a number of
195
- # documentation sites discourage its use. Thus, it's possible that, depending on the server API
196
- # framework, the DELETE request could be rejected. As such, we're disallowing it here, BUT if we
197
- # get feedback from users that it should be supported, we can add support for it.
198
- raise 'DELETE requests without URI parameters are not allowed'
199
- # define_method(endpoint_name_as_sym) do |auth_token|
200
- # RestClientResources.execute_delete_authenticated self, endpoint, auth_token, {}
201
- # end
202
262
  end
203
263
  end
204
264
  else
205
- raise 'Unauthenticated DELETE requests are not allowed'
206
- # Bubbles::RestEnvironment.class_exec do
207
- # define_method(endpoint_name_as_sym) do
208
- # RestClientResources.execute_delete_unauthenticated self, endpoint
209
- # end
210
- # end
265
+ # XXX_jwir3: While MDN states that DELETE requests with a body are allowed, it seems that a number of
266
+ # documentation sites discourage its use. Thus, it's possible that, depending on the server API
267
+ # framework, the DELETE request could be rejected. In addition, RestClient doesn't seem to support DELETE
268
+ # requests with a body, so we're a bit stuck on this one, even if we wanted to support it.
269
+ raise 'DELETE requests without URI parameters are not allowed'
211
270
  end
212
271
  elsif endpoint.method == :patch
213
272
  if endpoint.authenticated?
214
273
  Bubbles::RestEnvironment.class_exec do
215
274
  if endpoint.has_uri_params?
216
275
  define_method(endpoint_name_as_sym) do |auth_token, uri_params, data|
217
- RestClientResources.execute_patch_authenticated self, endpoint, auth_token, uri_params, data
276
+ RestClientResources.execute_patch_authenticated self, endpoint, auth_token, uri_params, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
218
277
  end
219
278
  else
220
279
  define_method(endpoint_name_as_sym) do |auth_token, data|
221
- # TODO: Nothing tests this case. We need something to test this case or we run the risk of
222
- # it having bugs (uri_params was nil previously!)
223
- RestClientResources.execute_patch_authenticated self, endpoint, auth_token, {}, data
280
+ RestClientResources.execute_patch_authenticated self, endpoint, auth_token, {}, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
224
281
  end
225
282
  end
226
283
  end
@@ -228,11 +285,11 @@ module Bubbles
228
285
  Bubbles::RestEnvironment.class_exec do
229
286
  if endpoint.has_uri_params?
230
287
  define_method(endpoint_name_as_sym) do |uri_params, data|
231
- RestClientResources.execute_patch_unauthenticated self, endpoint, uri_params, data
288
+ RestClientResources.execute_patch_unauthenticated self, endpoint, uri_params, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
232
289
  end
233
290
  else
234
291
  define_method(endpoint_name_as_sym) do |data|
235
- RestClientResources.execute_patch_unauthenticated self, endpoint, {}, data
292
+ RestClientResources.execute_patch_unauthenticated self, endpoint, {}, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
236
293
  end
237
294
  end
238
295
  end
@@ -242,26 +299,23 @@ module Bubbles
242
299
  Bubbles::RestEnvironment.class_exec do
243
300
  if endpoint.has_uri_params?
244
301
  define_method(endpoint_name_as_sym) do |auth_token, uri_params, data|
245
- RestClientResources.execute_put_authenticated self, endpoint, auth_token, uri_params, data
302
+ RestClientResources.execute_put_authenticated self, endpoint, auth_token, uri_params, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
246
303
  end
247
304
  else
248
305
  define_method(endpoint_name_as_sym) do |auth_token, data|
249
- # TODO: Nothing tests this case. We need something to test this case or we run the risk of
250
- # it having bugs (uri_params was nil previously!)
251
- RestClientResources.execute_put_authenticated self, endpoint, auth_token, {}, data
306
+ RestClientResources.execute_put_authenticated self, endpoint, auth_token, {}, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
252
307
  end
253
308
  end
254
309
  end
255
310
  else
256
- # raise 'Unauthenticated PUT requests are not implemented'
257
311
  Bubbles::RestEnvironment.class_exec do
258
312
  if endpoint.has_uri_params?
259
313
  define_method(endpoint_name_as_sym) do |uri_params, data|
260
- RestClientResources.execute_put_unauthenticated self, endpoint, uri_params, data
314
+ RestClientResources.execute_put_unauthenticated self, endpoint, uri_params, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
261
315
  end
262
316
  else
263
317
  define_method(endpoint_name_as_sym) do |data|
264
- RestClientResources.execute_put_unauthenticated self, endpoint, {}, data
318
+ RestClientResources.execute_put_unauthenticated self, endpoint, {}, data, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
265
319
  end
266
320
  end
267
321
  end
@@ -271,23 +325,11 @@ module Bubbles
271
325
  Bubbles::RestEnvironment.class_exec do
272
326
  if endpoint.has_uri_params?
273
327
  define_method(endpoint_name_as_sym) do |auth_token, uri_params|
274
- RestClientResources.execute_head_authenticated self, endpoint, auth_token, uri_params
328
+ RestClientResources.execute_head_authenticated self, endpoint, auth_token, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
275
329
  end
276
330
  else
277
331
  define_method(endpoint_name_as_sym) do |auth_token|
278
- RestClientResources.execute_head_authenticated self, endpoint, auth_token, {}
279
- end
280
- end
281
- end
282
- elsif endpoint.api_key_required?
283
- Bubbles::RestEnvironment.class_exec do
284
- if endpoint.has_uri_params?
285
- define_method(endpoint_name_as_sym) do |uri_params|
286
- RestClientResources.execute_head_unauthenticated_with_uri_params self, endpoint, self.api_key, uri_params
287
- end
288
- else
289
- define_method(endpoint_name_as_sym) do
290
- RestClientResources.execute_head_unauthenticated self, endpoint, self.api_key, nil
332
+ RestClientResources.execute_head_authenticated self, endpoint, auth_token, {}, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
291
333
  end
292
334
  end
293
335
  end
@@ -295,11 +337,11 @@ module Bubbles
295
337
  Bubbles::RestEnvironment.class_exec do
296
338
  if endpoint.has_uri_params?
297
339
  define_method(endpoint_name_as_sym) do |uri_params|
298
- RestClientResources.execute_head_unauthenticated self, endpoint, uri_params, {}
340
+ RestClientResources.execute_head_unauthenticated self, endpoint, uri_params, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
299
341
  end
300
342
  else
301
343
  define_method(endpoint_name_as_sym) do
302
- RestClientResources.execute_head_unauthenticated self, endpoint, {}, {}
344
+ RestClientResources.execute_head_unauthenticated self, endpoint, {}, endpoint.additional_headers, self.get_api_key_if_needed(endpoint), self.api_key_name
303
345
  end
304
346
  end
305
347
  end
@@ -74,13 +74,14 @@ module Bubbles
74
74
  # @param [Array<Symbol>] encode_authorization Parameters that should be treated as authorization parameters and
75
75
  # encoded using a Base64 encoding.
76
76
  #
77
- def initialize(method, location, auth_required = false, api_key_required = false, name = nil, return_type = :body_as_string, encode_authorization = {})
77
+ def initialize(method, location, auth_required = false, api_key_required = false, name = nil, return_type = :body_as_string, encode_authorization = {}, headers = {})
78
78
  @method = method
79
79
  @location = location
80
80
  @auth_required = auth_required
81
81
  @api_key_required = api_key_required
82
82
  @name = name
83
83
  @encode_authorization = encode_authorization
84
+ @additional_headers = headers
84
85
 
85
86
  unless Endpoint::RETURN_TYPES.include? return_type.to_s
86
87
  return_type = :body_as_string
@@ -145,13 +146,10 @@ module Bubbles
145
146
  #
146
147
  # @param [RestEnvironment] env The +RestEnvironment+ to use to access this +Endpoint+.
147
148
  #
148
- # @return [String] A +String+ containing the full URL to access this +Endpoint+ on the given {RestEnvironment}.
149
+ # @return [Addressable::URI] An +Addressable::URI+ containing the full URL to access this +Endpoint+ on the given
150
+ # +RestEnvironment+.
149
151
  #
150
152
  def get_expanded_url(env, uri_params = {})
151
- unless uri_params
152
- uri_params = {}
153
- end
154
-
155
153
  url = get_base_url env
156
154
 
157
155
  if is_complex?
@@ -239,7 +237,7 @@ module Bubbles
239
237
  # for the +Endpoint+, to be defined on {RestClientResources}; false, otherwise.
240
238
  #
241
239
  def name?
242
- @name == nil
240
+ @name != nil
243
241
  end
244
242
 
245
243
  ##
@@ -272,5 +270,17 @@ module Bubbles
272
270
  def has_uri_params?
273
271
  !@uri_params.empty?
274
272
  end
273
+
274
+ def additional_headers
275
+ unless @additional_headers
276
+ @additional_headers = {}
277
+ end
278
+
279
+ @additional_headers
280
+ end
281
+
282
+ def has_additional_headers?
283
+ not additional_headers.empty?
284
+ end
275
285
  end
276
286
  end