bubbles-rest-client 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f8bdd1fabbb4307f261d1d1a0964d3e6e1cd0ab
4
- data.tar.gz: 91aafd3870051c1960a1a3038a0625b2383f48ca
3
+ metadata.gz: 3db39174193ea887659c8e1d859048526b0c5335
4
+ data.tar.gz: 8254a56110041009e0e03c32aae4b1a1de08b914
5
5
  SHA512:
6
- metadata.gz: c47bd2636eb96aff3ffd058ea682e22547099f96c8f2f683d8b2b8b2a371cd5be29ed63d39651723eef283ef4f4620d638cc99d8e9f2b87c85ea6e93e176d7c6
7
- data.tar.gz: 90572682aa9b7f686b21e96758f0ee50af6adc20d902f5894996e42457fb3ed496305bb18c8f52cd1f1e0a07cfdca5d04eb22ad18d4a4dbaa8be8dd9f9349c41
6
+ metadata.gz: 8c0f6e722b868cf82d60f0a12e17b3ea24cc59f65ea756e93bf07d906670b49dd700a44f2f2631b0d1ef6ff264bfa0c13d1c74dfaf2e26e7944f1d3ae175924e
7
+ data.tar.gz: 3211a7eda8805bdba2678c551f73dd8212d188ce371a4a3a526010b8a6507071f5ba41d41ef93a253afa37bf99b5a3f955f9098f963d0b3f83dfbc79078744a7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bubbles-rest-client (0.0.7)
4
+ bubbles-rest-client (0.1.0)
5
5
  addressable (~> 2.5)
6
6
  rest-client (~> 2.0)
7
7
 
data/README.md CHANGED
@@ -22,3 +22,158 @@ GitHubService service = retrofit.create(GitHubService.class);
22
22
  What this does is allow you to focus on your _handling_ of the REST responses, rather than worrying about the boilerplate code required to set up the client side of the REST API.
23
23
 
24
24
  _bubbles_ is a Gem that seeks to provide this same behavior.
25
+
26
+ ## :warning: Limitations
27
+ **Please read this section before using!**
28
+
29
+ Currently, bubbles has a number of limitations that make it likely not suitable for use in a production environment. Each of these is tracked by an issue on our [issues page](https://github.com/FoamFactory/bubbles/issues).
30
+
31
+ - Passing an API key with a request is restricted to using `X-Api-Key` as a header key (#10).
32
+ - Some request methods (`PATCH`, `PUT`, `DELETE`) do not currently allow unauthenticated access. In other words, it is not possible to perform a `DELETE` request on your API without passing an authorization token. (#9)
33
+ - Only three types of environment are currently allowed. Only `local`, `staging` and `production` are recognized as possible environments to connect to for the purposes of using bubbles. You can add any scheme, host, and port to any of these, but the names are currently hardcoded, as is the number of possible hosts. (#4)
34
+ - Not all possible combinations of `has_uri_params`, `authenticated`, and `api_key_required` are tested. In some cases, such as with `GET` requests, there aren't any tests for possible configuration cases that might cause issues when combined. (#12)
35
+ - Usage of the `expect_json` configuration parameter is not intuitive. You should think of this as more of a "I want an object back from the API", rather than how it's worded. (#11)
36
+
37
+ If you're interested in working on any of the issues above, please feel free to submit a pull request and a member of our team will review that pull request within a couple of days.
38
+
39
+ ## Usage
40
+ If you're using Rails, it's suggested to have a `config/initializers/bubbles.rb` configuration file where you can easily configure your endpoints and environments. If you're not using Rails, then you can put this configuration just about anywhere, provided it's executed before where you want to use it.
41
+
42
+ ## Quickstart
43
+ In `config/initializers/bubbles.rb`, add the following:
44
+ ```ruby
45
+ require 'bubbles'
46
+
47
+ Bubbles.configure do |config|
48
+ config.endpoints = [
49
+ {
50
+ :method => :get,
51
+ :location => :version,
52
+ :authenticated => false,
53
+ :api_key_required => false
54
+ }
55
+ ]
56
+
57
+ config.local_environment = {
58
+ :scheme => 'http',
59
+ :host => '0.0.0.0',
60
+ :port => '1234'
61
+ }
62
+ end
63
+ ```
64
+
65
+ The `config.endpoints` section is where you configure which endpoints you want to support. The `config.local_environment` defines an environment, or remote configuration, for accessing the endpoint on a specific remote destination.
66
+
67
+ Now, you can use this endpoint with:
68
+ ```ruby
69
+ require 'bubbles'
70
+
71
+ ...
72
+
73
+ def version
74
+ resources = Bubbles::Resources.new
75
+
76
+ # The following will make a GET request to
77
+ # http://0.0.0.0:1234/version and return the result.
78
+ result = resources.local_environment.version
79
+
80
+ puts(result)
81
+ end
82
+ ```
83
+
84
+ ## Detailed Documentation
85
+ There are currently two parts to a bubbles configuration: the _environments_ and the _endpoints_. Bubbles is configured in a _bubbles configuration block_:
86
+ ```ruby
87
+ Bubbles.configure do |config|
88
+ ...
89
+ end
90
+ ```
91
+
92
+ This configuration block can be run at any time, but is typically set up in the initializer section of an app's startup. If desired, configuration can happen separately. That is, you can initialize environments within your initializer file and then initialize endpoints within another section of the application. Just note that when endpoints are defined, it overwrites _all_ endpoints of a configuration, not just the ones you choose to change.
93
+
94
+ ### Environments
95
+ Three environments are currently available to be set up within bubbles. These are:
96
+ - `local_environment` : Designed to be used for a local API for development testing.
97
+ - `staging_environment` : Designed to be used for a remote API for second-stage testing or production-like deployment.
98
+ - `production_environment` : Designed to be used for a production environment.
99
+
100
+ While the names are hardcoded, the environments can be used for anything - you could easily use a `local_environment` to store the information for one of your production servers.
101
+
102
+ #### Configuration of Environments
103
+ Environments are configured as part of the _bubbles configuration block_ and can have the following parameters:
104
+
105
+ - `scheme`: The scheme for accessing endpoints on this host. Should be one of `http` or `https`. Defaults to `http`.
106
+ - `host`: A domain name or IP address for the remote host to access for the environment. Defaults to `127.0.0.1`.
107
+ - `port`: The port to use to access the remote host. Defaults to `1234`.
108
+ - `api_key`: The API key to send along with requests for a given environment, if an API key is required. This is optional, and defaults to `nil`.
109
+
110
+ You can configure all three environments at once in the _bubbles configuration block_:
111
+ ```ruby
112
+ Bubbles.configure do |config|
113
+ config.local_environment = {
114
+ :scheme => 'http',
115
+ :host => '0.0.0.0',
116
+ :port => '1234'
117
+ }
118
+
119
+ config.staging_environment = {
120
+ :scheme => 'http',
121
+ :host => 'stage.api.foamfactory.com',
122
+ :port => '80'
123
+ }
124
+
125
+ config.production_environment = {
126
+ :scheme => 'https',
127
+ :host => 'api.foamfactory.com',
128
+ :port => '443'
129
+ }
130
+ end
131
+ ```
132
+
133
+ If you choose a scheme of `http` and leave off the `port` configuration variable, it will default to `80`. Similarly, `https` will default to a port of `443`.
134
+
135
+ #### Configuration of Endpoints
136
+ Endpoints are the meat and potatoes of REST interaction. By indicating a _method_, _uri_, _body_, and _headers_, you are effectively making a function call on a remote server.
137
+
138
+ _Endpoints_ are specified as an array of objects within the _bubbles configuration block_:
139
+
140
+ ```ruby
141
+ config.endpoints = [
142
+ # Individual endpoint definitions go here
143
+ ]
144
+ ```
145
+
146
+ When processing each of these endpoint definitions, a method is created on instances of `RestEnvironment` that allows you to call the method in question. For example, an endpoint defined as:
147
+ ```ruby
148
+ {
149
+ :method => :get,
150
+ :location => :version,
151
+ :authenticated => false,
152
+ :api_key_required => false
153
+ }
154
+ ```
155
+
156
+ will create a method on instances of `RestEnvironment` called `version`, which will execute the appropriate REST call (via `RestClient`) and return a `RestClient::Response` object.
157
+
158
+ Each _endpoint_ object can have the following attributes:
159
+
160
+ | Name | Description | Required? | Default |
161
+ | :--- | :------------------ | :-------: | :-----: |
162
+ | `method`| The HTTP method to use to access the API for this endpoint. Must be one of `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, or `HEAD`. | Yes | N/A |
163
+ | `location`| The path to access the endpoint. This is placed after the `host:port` section to build the URI. It may have URI parameters in the form of `{paramName}`. If a URI parameter is specified within the `location`, a `uri_params` hash will be expected to be passed to the calling method to replace the placeholder values. | Yes | N/A |
164
+ | `name` | The name to give the method created to make this REST call. | No | The value of the `location` parameter, with slashes (`/`) replaced with underscores (`_`). |
165
+ | `authorization` | Whether or not this endpoint requires authentication prior to executing the call. If true, then an `authorization_token` will be added to the method as a parameter to be passed when the method is called. This parameter will be placed in an `Authorization` header when the REST call is executed. | No | `false` |
166
+ | `api_key_required` | Whether or not an API key is required. If `true`, a parameter will be added to the method created to execute the REST API call named `api_key`. The value of this parameter will be set as the value of the `X-Api-Key` header when making the REST API call. | No | `false` |
167
+ | `expect_json` | Whether or not JSON is expected as the format of the `body` of both the Request and Response. Additionally, specifying `true` for this option will cause methods executing REST requests to return `OpenStruct` objects representing the fully-parsed JSON response (on success). See note under "Limitations", above, on using this parameter. | No | `false` |
168
+ | `encode_authorization` | Whether the `data` passed as part of the request should be re-encoded as an `Authorization: Basic` header (and Base64 encoded). Typically, this is only used for initial username/password authentication. | No | `false` |
169
+
170
+ ### Examples
171
+ #### GET the version of the software (unauthenticated, no API key required)
172
+
173
+ #### GET a specific user by id (authentication required)
174
+
175
+ #### POST a login (i.e. retrieve an authorization token)
176
+
177
+ #### DELETE a user by id
178
+
179
+ #### PATCH a user's information by providing a body containing information to update
data/bubbles.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Bubbles::VersionInformation.version_name
9
9
  spec.date = Date.today.strftime("%Y-%m-%d")
10
10
  spec.summary = 'FoamFactory REST Client'
11
- spec.homepage = 'http://www.foamfactorybrewing.com'
11
+ spec.homepage = 'https://github.com/FoamFactory/bubbles'
12
12
  spec.authors = ['Scott Johnson']
13
13
  spec.email = 'jaywir3@gmail.com'
14
14
  spec.files = %w(lib/bubbles.rb lib/bubbles/rest_environment.rb lib/bubbles/version.rb)
@@ -1,5 +1,6 @@
1
1
  require 'bubbles/rest_environment'
2
2
  require 'bubbles/endpoint'
3
+ require 'base64'
3
4
 
4
5
  module Bubbles
5
6
  class << self
@@ -41,14 +42,17 @@ module Bubbles
41
42
  @local_environment_scheme = 'http'
42
43
  @local_environment_host = '127.0.0.1'
43
44
  @local_environment_port = '1234'
45
+ @local_environment_api_key = nil
44
46
 
45
47
  @staging_environment_scheme = 'http'
46
48
  @staging_environment_host = '127.0.0.1'
47
49
  @staging_environment_port = '1234'
50
+ @staging_environment_api_key = nil
48
51
 
49
52
  @production_environment_scheme = 'http'
50
53
  @production_environment_host = '127.0.0.1'
51
54
  @production_environment_port = '1234'
55
+ @production_environment_api_key = nil
52
56
 
53
57
  @endpoints = Hash.new
54
58
  end
@@ -57,7 +61,7 @@ module Bubbles
57
61
  # Retrieve the local {RestEnvironment} object defined as part of this Configuration.
58
62
  #
59
63
  def local_environment
60
- RestEnvironment.new(@local_environment_scheme, @local_environment_host, @local_environment_port)
64
+ RestEnvironment.new(@local_environment_scheme, @local_environment_host, @local_environment_port, @local_environment_api_key)
61
65
  end
62
66
 
63
67
  ##
@@ -78,13 +82,14 @@ module Bubbles
78
82
  @local_environment_scheme = env[:scheme]
79
83
  @local_environment_host = env[:host]
80
84
  @local_environment_port = env[:port]
85
+ @local_environment_api_key = env[:api_key]
81
86
  end
82
87
 
83
88
  ##
84
89
  # Retrieve the staging {RestEnvironment} object defined as part of this Configuration.
85
90
  #
86
91
  def staging_environment
87
- RestEnvironment.new(@staging_environment_scheme, @staging_environment_host, @staging_environment_port)
92
+ RestEnvironment.new(@staging_environment_scheme, @staging_environment_host, @staging_environment_port, @staging_environment_api_key)
88
93
  end
89
94
 
90
95
  ##
@@ -105,13 +110,14 @@ module Bubbles
105
110
  @staging_environment_scheme = env[:scheme]
106
111
  @staging_environment_host = env[:host]
107
112
  @staging_environment_port = env[:port]
113
+ @staging_environment_api_key = env[:api_key]
108
114
  end
109
115
 
110
116
  ##
111
117
  # Retrieve the production {RestEnvironment} object defined as part of this Configuration.
112
118
  #
113
119
  def production_environment
114
- RestEnvironment.new(@production_environment_scheme, @production_environment_host, @production_environment_port)
120
+ RestEnvironment.new(@production_environment_scheme, @production_environment_host, @production_environment_port, @production_environment_api_key)
115
121
  end
116
122
 
117
123
  ##
@@ -124,7 +130,7 @@ module Bubbles
124
130
  # config.production_environment = {
125
131
  # :scheme => 'https',
126
132
  # :host => 'api.somehost.com',
127
- # :port => '443'
133
+ # :port => '443',
128
134
  # }
129
135
  # end
130
136
  #
@@ -132,6 +138,7 @@ module Bubbles
132
138
  @production_environment_scheme = env[:scheme]
133
139
  @production_environment_host = env[:host]
134
140
  @production_environment_port = env[:port]
141
+ @production_environment_api_key = env[:api_key]
135
142
  end
136
143
 
137
144
  ##
@@ -160,7 +167,7 @@ module Bubbles
160
167
  def endpoints=(endpoints)
161
168
  new_endpoints = Hash.new
162
169
  endpoints.each do |ep|
163
- endpoint_object = Endpoint.new ep[:method], ep[:location].to_s, ep[:authenticated], ep[:api_key_required], ep[:name]
170
+ endpoint_object = Endpoint.new ep[:method], ep[:location].to_s, ep[:authenticated], ep[:api_key_required], ep[:name], ep[:expect_json], ep[:encode_authorization]
164
171
 
165
172
  new_endpoints[endpoint_object.get_key_string] = endpoint_object
166
173
  end
@@ -184,8 +191,14 @@ module Bubbles
184
191
  if endpoint.method == :get
185
192
  if endpoint.authenticated?
186
193
  Bubbles::RestEnvironment.class_exec do
187
- define_method(endpoint_name_as_sym) do |auth_token|
188
- RestClientResources.execute_get_authenticated self, endpoint, auth_token
194
+ if endpoint.has_uri_params?
195
+ define_method(endpoint_name_as_sym) do |auth_token, uri_params|
196
+ RestClientResources.execute_get_authenticated self, endpoint, auth_token, uri_params
197
+ end
198
+ else
199
+ define_method(endpoint_name_as_sym) do |auth_token|
200
+ RestClientResources.execute_get_authenticated self, endpoint, auth_token, {}
201
+ end
189
202
  end
190
203
  end
191
204
  else
@@ -195,6 +208,155 @@ module Bubbles
195
208
  end
196
209
  end
197
210
  end
211
+ elsif endpoint.method == :post
212
+ if endpoint.authenticated?
213
+ Bubbles::RestEnvironment.class_exec do
214
+ define_method(endpoint_name_as_sym) do |auth_token, data|
215
+ RestClientResources.execute_post_authenticated self, endpoint, auth_token, data
216
+ end
217
+ end
218
+ else
219
+ if endpoint.api_key_required?
220
+ Bubbles::RestEnvironment.class_exec do
221
+ define_method(endpoint_name_as_sym) do |data|
222
+ additional_headers = {}
223
+ if endpoint.encode_authorization_header?
224
+ count = 0
225
+ auth_value = ''
226
+ endpoint.encode_authorization.each { |auth_key|
227
+ if data[auth_key]
228
+ if count > 0
229
+ auth_value = auth_value + ':' + data[auth_key]
230
+ else
231
+ auth_value = data[auth_key]
232
+ end
233
+
234
+ count = count + 1
235
+
236
+ data.delete(auth_key)
237
+ end
238
+ }
239
+
240
+ additional_headers[:Authorization] = 'Basic ' + Base64.strict_encode64(auth_value)
241
+ end
242
+
243
+ RestClientResources.execute_post_with_api_key self, endpoint, self.api_key, data, additional_headers
244
+ end
245
+ end
246
+ else
247
+ raise 'Unauthenticated POST requests without an API key are not allowed'
248
+ end
249
+ end
250
+ elsif endpoint.method == :delete
251
+ if endpoint.authenticated?
252
+ Bubbles::RestEnvironment.class_exec do
253
+ if endpoint.has_uri_params?
254
+ define_method(endpoint_name_as_sym) do |auth_token, uri_params|
255
+ RestClientResources.execute_delete_authenticated self, endpoint, auth_token, uri_params
256
+ end
257
+ else
258
+ # NOTE: While MDN states that DELETE requests with a body are allowed, it seems that a number of
259
+ # documentation sites discourage its use. Thus, it's possible that, depending on the server API
260
+ # framework, the DELETE request could be rejected. As such, we're disallowing it here, BUT if we
261
+ # get feedback from users that it should be supported, we can add support for it.
262
+ raise 'DELETE requests without URI parameters are not allowed'
263
+ # define_method(endpoint_name_as_sym) do |auth_token|
264
+ # RestClientResources.execute_delete_authenticated self, endpoint, auth_token, {}
265
+ # end
266
+ end
267
+ end
268
+ else
269
+ raise 'Unauthenticated DELETE requests are not allowed'
270
+ # Bubbles::RestEnvironment.class_exec do
271
+ # define_method(endpoint_name_as_sym) do
272
+ # RestClientResources.execute_delete_unauthenticated self, endpoint
273
+ # end
274
+ # end
275
+ end
276
+ elsif endpoint.method == :patch
277
+ if endpoint.authenticated?
278
+ Bubbles::RestEnvironment.class_exec do
279
+ if endpoint.has_uri_params?
280
+ define_method(endpoint_name_as_sym) do |auth_token, uri_params, data|
281
+ RestClientResources.execute_patch_authenticated self, endpoint, auth_token, uri_params, data
282
+ end
283
+ else
284
+ define_method(endpoint_name_as_sym) do |auth_token, data|
285
+ RestClientResources.execute_patch_authenticated self, endpoint, auth_token, nil, data
286
+ end
287
+ end
288
+ end
289
+ else
290
+ raise 'Unauthenticated PATCH requests are not implemented'
291
+ # Bubbles::RestEnvironment.class_exec do
292
+ # define_method(endpoint_name_as_sym) do
293
+ # RestClientResources.execute_delete_unauthenticated self, endpoint
294
+ # end
295
+ # end
296
+ end
297
+ elsif endpoint.method == :put
298
+ if endpoint.authenticated?
299
+ Bubbles::RestEnvironment.class_exec do
300
+ if endpoint.has_uri_params?
301
+ define_method(endpoint_name_as_sym) do |auth_token, uri_params, data|
302
+ RestClientResources.execute_put_authenticated self, endpoint, auth_token, uri_params, data
303
+ end
304
+ else
305
+ define_method(endpoint_name_as_sym) do |auth_token, data|
306
+ RestClientResources.execute_put_authenticated self, endpoint, auth_token, nil, data
307
+ end
308
+ end
309
+ end
310
+ else
311
+ raise 'Unauthenticated PUT requests are not implemented'
312
+ # Bubbles::RestEnvironment.class_exec do
313
+ # define_method(endpoint_name_as_sym) do
314
+ # RestClientResources.execute_delete_unauthenticated self, endpoint
315
+ # end
316
+ # end
317
+ end
318
+ elsif endpoint.method == :head
319
+ if endpoint.authenticated?
320
+ Bubbles::RestEnvironment.class_exec do
321
+ if endpoint.has_uri_params?
322
+ define_method(endpoint_name_as_sym) do |auth_token, uri_params|
323
+ RestClientResources.execute_head_authenticated self, endpoint, auth_token, uri_params
324
+ end
325
+ else
326
+ define_method(endpoint_name_as_sym) do |auth_token|
327
+ RestClientResources.execute_head_authenticated self, endpoint, auth_token, {}
328
+ end
329
+ end
330
+ end
331
+ elsif endpoint.api_key_required?
332
+ Bubbles::RestEnvironment.class_exec do
333
+ if endpoint.has_uri_params?
334
+ define_method(endpoint_name_as_sym) do |api_key, uri_params|
335
+ additional_headers = {}
336
+ additional_headers['X-Api-Key'] = api_key
337
+ RestClientResources.execute_head_unauthenticated self, endpoint, uri_params, additional_headers
338
+ end
339
+ else
340
+ define_method(endpoint_name_as_sym) do |api_key|
341
+ additional_headers = {}
342
+ additional_headers['X-Api-Key'] = api_key
343
+ RestClientResources.execute_head_unauthenticated self, endpoint, {}, additional_headers
344
+ end
345
+ end
346
+ end
347
+ else
348
+ Bubbles::RestEnvironment.class_exec do
349
+ if endpoint.has_uri_params?
350
+ define_method(endpoint_name_as_sym) do |uri_params|
351
+ RestClientResources.execute_head_unauthenticated self, endpoint, uri_params, {}
352
+ end
353
+ else
354
+ define_method(endpoint_name_as_sym) do
355
+ RestClientResources.execute_head_unauthenticated self, endpoint, {}, {}
356
+ end
357
+ end
358
+ end
359
+ end
198
360
  end
199
361
  end
200
362
  end
@@ -9,22 +9,42 @@ module Bubbles
9
9
  # Endpoint can be used with any +RestEnvironment+.
10
10
  #
11
11
  class Endpoint
12
- ## Controls the method used to access the endpoint. Must be one of {Endpoint::Methods}.
12
+ ##
13
+ # Controls the method used to access the endpoint. Must be one of {Endpoint::Methods}.
13
14
  # @return [Symbol] the method used to access the endpoint. Will always be one of the symbols defined in {Endpoint::METHODS}.
14
15
  attr_accessor :method
15
16
 
16
- ## Controls the location, relative to the web root of the host, used to access the endpoint.
17
+ ##
18
+ # Controls the location, relative to the web root of the host, used to access the endpoint.
17
19
  # @return [String] the location relative to the web root of the host used to access the endpoint
18
20
  attr_accessor :location
19
21
 
20
- ## Controls whether authentication is required to access this endpoint. Defaults to false.
22
+ ##
23
+ # Controls whether authentication is required to access this endpoint. Defaults to false.
21
24
  # @return [Boolean] true, if authentication is required to access this endpoint; false, otherwise.
22
25
  attr_accessor :authentication_required
23
26
 
24
- ## Controls whether an API key is required to access this endpoint. Defaults to false.
27
+ ##
28
+ # Controls whether an API key is required to access this endpoint. Defaults to false.
25
29
  # @return [Boolean] true, if an API key is required to access this endpoint; false, otherwise.
26
30
  attr_accessor :api_key_required
27
31
 
32
+ ##
33
+ # Controls whether JSON is the expected form of output from this +Endpoint+.
34
+ # @return [Boolean] true, if JSON is the expected form of output from this +Endpoint+; false, otherwise.
35
+ attr_accessor :expect_json
36
+
37
+ ##
38
+ # Controls which data values should be encoded as part of an Authorization header. They will be separated with a
39
+ # colon in the order they are received and Base64-encoded.
40
+ # @return [Array] An array of +Symbol+s specifying which of the data attributes should be Base64-encoded as part of
41
+ # an Authorization header. The values will be encoded in the order they are received.
42
+ attr_accessor :encode_authorization
43
+
44
+ ##
45
+ # An array of parameters that are specified on the URI of this endpoint for each call.
46
+ attr_accessor :uri_params
47
+
28
48
  ## A template for specifying the complete URL for endpoints.
29
49
  API_URL = ::Addressable::Template.new("{scheme}://{host}/{endpoint}")
30
50
 
@@ -33,7 +53,7 @@ module Bubbles
33
53
 
34
54
 
35
55
  ## The HTTP methods supported by a rest client utilizing Bubbles.
36
- METHODS = %w[get].freeze
56
+ METHODS = %w[get post patch put delete head].freeze
37
57
 
38
58
  ##
39
59
  # Construct a new instance of an Endpoint.
@@ -46,18 +66,32 @@ module Bubbles
46
66
  # +false+.
47
67
  # @param [String] name An optional name which will be given to the method that will execute this {Endpoint} within
48
68
  # the context of a {RestClientResources} object.
69
+ # @param [Boolean] expect_json Whether or not to expect a JSON response from this +Endpoint+. Defaults to +false+.
49
70
  #
50
- def initialize(method, location, auth_required = false, api_key_required = false, name = nil)
71
+ def initialize(method, location, auth_required = false, api_key_required = false, name = nil, expect_json = false, encode_authorization = {})
51
72
  @method = method
52
73
  @location = location
53
74
  @auth_required = auth_required
54
75
  @api_key_required = api_key_required
55
76
  @name = name
77
+ @expect_json = expect_json
78
+ @encode_authorization = encode_authorization
79
+ @uri_params = []
56
80
 
57
81
  # Strip the leading slash from the endpoint location, if it's there
58
82
  if @location.to_s[0] == '/'
59
83
  @location = @location.to_s.slice(1, @location.to_s.length)
60
84
  end
85
+
86
+ # Extract URI parameters and create symbols for them
87
+ # URI parameters are enclosed by curly braces '{' and '}'
88
+ @location.to_s.split('/').each do |uri_segment|
89
+
90
+ match_data = /\{(.*)\}/.match(uri_segment)
91
+ unless match_data == nil
92
+ @uri_params.push(match_data[1].to_sym)
93
+ end
94
+ end
61
95
  end
62
96
 
63
97
  ##
@@ -101,16 +135,22 @@ module Bubbles
101
135
  #
102
136
  # @return [String] A +String+ containing the full URL to access this +Endpoint+ on the given {RestEnvironment}.
103
137
  #
104
- def get_expanded_url(env)
138
+ def get_expanded_url(env, uri_params = {})
105
139
  url = get_base_url env
106
140
 
107
141
  if is_complex?
108
- special_url_string = '{scheme}://{environment_host}/'
142
+ special_url_string = '{scheme}://{host}/'
109
143
  unless @port == 80 || @port == 443
110
- special_url_string = '{scheme}://{environment_host}:{port}/'
144
+ special_url_string = '{scheme}://{host}:{port}/'
111
145
  end
112
146
 
113
147
  special_url_string = special_url_string + @location
148
+
149
+ uri_params.each do |param, value|
150
+ needle = "{#{param.to_s}}"
151
+ special_url_string = special_url_string.sub(needle, value.to_s)
152
+ end
153
+
114
154
  url = ::Addressable::Template.new(special_url_string)
115
155
 
116
156
  return url.expand(scheme: env.scheme, host: env.host, port: env.port)
@@ -149,6 +189,14 @@ module Bubbles
149
189
  @auth_required
150
190
  end
151
191
 
192
+ ##
193
+ # Determine if an API key is required
194
+ #
195
+ # @return [Boolean] true, if an API key is required to make the request; false, otherwise.
196
+ def api_key_required?
197
+ api_key_required
198
+ end
199
+
152
200
  ##
153
201
  # Set the name of the method on {RestClientResources} used to access this {Endpoint}.
154
202
  #
@@ -177,5 +225,19 @@ module Bubbles
177
225
  def name?
178
226
  @name == nil
179
227
  end
228
+
229
+ ##
230
+ # Whether or not an Authorization header should be Base64-encoded.
231
+ #
232
+ # @return [Boolean] true, if attributes from the data array have been specified to be Base64-encoded as part of an
233
+ # Authorization header; false, otherwise.
234
+ #
235
+ def encode_authorization_header?
236
+ @encode_authorization.length > 0
237
+ end
238
+
239
+ def has_uri_params?
240
+ !@uri_params.empty?
241
+ end
180
242
  end
181
243
  end
@@ -44,26 +44,14 @@ module Bubbles
44
44
  # @return [RestClient::Response] The +Response+ resulting from the execution of the GET call.
45
45
  #
46
46
  def self.execute_get_unauthenticated(env, endpoint)
47
- url = endpoint.get_expanded_url env
48
-
49
- begin
47
+ execute_rest_call(env, endpoint, nil, nil, nil) do |env, url, data, headers|
50
48
  if env.scheme == 'https'
51
- response = RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
52
- .get({
53
- :content_type => :json,
54
- :accept => :json
55
- })
49
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
50
+ .get(headers)
56
51
  else
57
- response = RestClient.get(url.to_s,
58
- {
59
- :content_type => :json
60
- })
52
+ next RestClient.get(url.to_s, headers)
61
53
  end
62
- rescue Errno::ECONNREFUSED
63
- return {:error => 'Unable to connect to host ' + env.host.to_s + ':' + env.port.to_s}.to_json
64
54
  end
65
-
66
- response
67
55
  end
68
56
 
69
57
  ##
@@ -74,32 +62,190 @@ module Bubbles
74
62
  # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
75
63
  # @param [Endpoint] endpoint The +Endpoint+ which should be requested
76
64
  # @param [String] auth_token The authorization token to use for authentication.
65
+ # @param [Hash] uri_params A +Hash+ of identifiers to values to replace in the URI string.
77
66
  #
78
67
  # @return [RestClient::Response] The +Response+ resulting from the execution of the GET call.
79
68
  #
80
- def self.execute_get_authenticated(env, endpoint, auth_token)
81
- url = endpoint.get_expanded_url env
69
+ def self.execute_get_authenticated(env, endpoint, auth_token, uri_params)
70
+ execute_rest_call(env, endpoint, nil, auth_token, nil, uri_params) do |env, url, data, headers|
71
+ if env.scheme == 'https'
72
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
73
+ .get(headers)
74
+ else
75
+ next RestClient.get(url.to_s, headers)
76
+ end
77
+ end
78
+ end
82
79
 
83
- begin
80
+ ##
81
+ # Execute a HEAD request without authentication.
82
+ #
83
+ # This is the same as a GET request, but will only return headers and not the response body.
84
+ #
85
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
86
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
87
+ #
88
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the GET call.
89
+ #
90
+ def self.execute_head_unauthenticated(env, endpoint, uri_params, additional_headers)
91
+ execute_rest_call(env, endpoint, nil, nil, additional_headers, uri_params) do |env, url, data, headers|
84
92
  if env.scheme == 'https'
85
- response = RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
86
- .get({
87
- :authorization => 'Bearer ' + auth_token,
88
- :content_type => :json,
89
- :accept => :json
90
- })
93
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
94
+ .head(headers)
91
95
  else
92
- response = RestClient.get(url.to_s,
93
- {
94
- :authorization => 'Bearer ' + auth_token,
95
- :content_type => :json
96
- })
96
+ next RestClient.head(url.to_s, headers)
97
97
  end
98
- rescue Errno::ECONNREFUSED
99
- return {:error => 'Unable to connect to host ' + env.host.to_s + ':' + env.port.to_s}.to_json
100
98
  end
99
+ end
101
100
 
102
- response
101
+ ##
102
+ # Execute a HEAD request with authentication.
103
+ #
104
+ # Currently, only Authorization: Bearer is supported. This is the same as a GET request, but will only return
105
+ # headers and not the response body.
106
+ #
107
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
108
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
109
+ # @param [String] auth_token The authorization token to use for authentication.
110
+ # @param [Hash] uri_params A +Hash+ of identifiers to values to replace in the URI string.
111
+ #
112
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the GET call.
113
+ #
114
+ def self.execute_head_authenticated(env, endpoint, auth_token, uri_params)
115
+ execute_rest_call(env, endpoint, nil, auth_token, nil, uri_params) do |env, url, data, headers|
116
+ if env.scheme == 'https'
117
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
118
+ .head(headers)
119
+ else
120
+ next RestClient.head(url.to_s, headers)
121
+ end
122
+ end
123
+ end
124
+
125
+ ##
126
+ # Execute a POST request without authentication, but requiring an API key.
127
+ #
128
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
129
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
130
+ # @param [String] api_key The API key to use to process the request. Will be placed in an 'X-API-KEY' header.
131
+ # @param [Hash] data A +Hash+ of key-value pairs that will be sent in the body of the http request.
132
+ # @param [Hash] headers (Optional) A +Hash+ of key-value pairs that will be sent as HTTP headers as part of the
133
+ # request. Defaults to +nil+.
134
+ #
135
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the POST call.
136
+ #
137
+ def self.execute_post_with_api_key(env, endpoint, api_key, data, headers=nil)
138
+ additional_headers = {
139
+ 'X-Api-Key' => api_key
140
+ }
141
+
142
+ unless headers.nil?
143
+ headers.each { |nextHeader|
144
+ additional_headers[nextHeader[0]] = nextHeader[1]
145
+ }
146
+ end
147
+
148
+ execute_rest_call(env, endpoint, data, nil, additional_headers) do |env, url, data, headers|
149
+ if env.scheme == 'https'
150
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
151
+ .post(data.to_json, additional_headers)
152
+ else
153
+ next RestClient.post url.to_s, data.to_json, additional_headers
154
+ end
155
+ end
156
+ end
157
+
158
+ ##
159
+ # Execute a POST request with authentication in the form of an authorization token.
160
+ #
161
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
162
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
163
+ # @param [String] auth_token The authorization token retrieved during some former authentication call. Will be
164
+ # placed into a Authorization header.
165
+ # @param [Hash] data A +Hash+ of key-value pairs that will be sent in the body of the http request.
166
+ #
167
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the POST call.
168
+ #
169
+ def self.execute_post_authenticated(env, endpoint, auth_token, data)
170
+ return execute_rest_call(env, endpoint, data, auth_token, nil) do |env, url, data, headers|
171
+ if env.scheme == 'https'
172
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
173
+ .post(data.to_json, headers)
174
+
175
+ else
176
+ next RestClient.post(url.to_s, data.to_json, headers)
177
+ end
178
+ end
179
+ end
180
+
181
+ ##
182
+ # Execute a PATCH request with authentication in the form of an authorization token.
183
+ #
184
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
185
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
186
+ # @param [String] auth_token The authorization token retrieved during some former authentication call. Will be
187
+ # placed into a Authorization header.
188
+ # @param [Hash] uri_params A +Hash+ of identifiers to values to replace in the URI string.
189
+ # @param [Hash] data A +Hash+ of key-value pairs that will be sent in the body of the http request.
190
+ #
191
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the PATCH call.
192
+ #
193
+ def self.execute_patch_authenticated(env, endpoint, auth_token, uri_params, data)
194
+ return execute_rest_call(env, endpoint, data, auth_token, nil, uri_params) do |env, url, data, headers|
195
+ if env.scheme == 'https'
196
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
197
+ .patch(data.to_json, headers)
198
+
199
+ else
200
+ next RestClient.patch(url.to_s, data.to_json, headers)
201
+ end
202
+ end
203
+ end
204
+
205
+ ##
206
+ # Execute a PUT request with authentication in the form of an authorization token.
207
+ #
208
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
209
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
210
+ # @param [String] auth_token The authorization token retrieved during some former authentication call. Will be
211
+ # placed into a Authorization header.
212
+ # @param [Hash] uri_params A +Hash+ of identifiers to values to replace in the URI string.
213
+ # @param [Hash] data A +Hash+ of key-value pairs that will be sent in the body of the http request.
214
+ #
215
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the PUT call.
216
+ #
217
+ def self.execute_put_authenticated(env, endpoint, auth_token, uri_params, data)
218
+ return execute_rest_call(env, endpoint, data, auth_token, nil, uri_params) do |env, url, data, headers|
219
+ if env.scheme == 'https'
220
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
221
+ .put(data.to_json, headers)
222
+
223
+ else
224
+ next RestClient.put(url.to_s, data.to_json, headers)
225
+ end
226
+ end
227
+ end
228
+
229
+ ##
230
+ # Execute a DELETE request with authentication in the form of an authorization token.
231
+ #
232
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to execute the request
233
+ # @param [Endpoint] endpoint The +Endpoint+ which should be requested
234
+ # @param [String] auth_token The authorization token retrieved during some former authentication call. Will be
235
+ # placed into a Authorization header.
236
+ # @param [Hash] uri_params A +Hash+ of identifiers to values to replace in the URI string.
237
+ #
238
+ # @return [RestClient::Response] The +Response+ resulting from the execution of the DELETE call.
239
+ #
240
+ def self.execute_delete_authenticated(env, endpoint, auth_token, uri_params)
241
+ execute_rest_call(env, endpoint, nil, auth_token, nil, uri_params) do |env, url, data, headers|
242
+ if env.scheme == 'https'
243
+ next RestClient::Resource.new(url.to_s, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
244
+ .delete(headers)
245
+ else
246
+ next RestClient.delete(url.to_s, headers)
247
+ end
248
+ end
103
249
  end
104
250
 
105
251
  ##
@@ -120,5 +266,65 @@ module Bubbles
120
266
 
121
267
  self.local_environment
122
268
  end
269
+
270
+ private
271
+
272
+ ##
273
+ # Execute a REST call to the API.
274
+ #
275
+ # This is the workhorse of the +RestClientResources+ class. It performs the necessary setup of headers and the HTTP
276
+ # request, and then executes the remote API call.
277
+ #
278
+ # @param [RestEnvironment] env The +RestEnvironment+ to use to make this API call. Must not be +nil+.
279
+ # @param [Endpoint] The +Endpoint+ to call. Must not be +nil+.
280
+ # @param [Hash] The body of the request. May be +nil+ or empty for requests not requiring a body.
281
+ # @param [String] auth_token The authorization token used to authenticate to the API. May be +nil+ for requests that
282
+ # don't require authentication.
283
+ # @param [Hash] headers A +Hash+ of key-value pairs to add to the HTTP request as headers. May be +nil+ if none are
284
+ # required.
285
+ # @param [Block] block The block to execute that actually performs the HTTP request.
286
+ #
287
+ # @return [RestClient::Response|OpenStruct] If "expect_json" is enabled for the +Endpoint+ being executed, then this
288
+ # will return an +OpenStruct+; otherwise, the +Response+ will be returned.
289
+ #
290
+ def self.execute_rest_call(env, endpoint, data, auth_token, headers, uri_params = {}, &block)
291
+ unless block
292
+ raise ArgumentError('This method requires that a block is given.')
293
+ end
294
+
295
+ url = endpoint.get_expanded_url env, uri_params
296
+
297
+ begin
298
+ if data == nil
299
+ data = {}
300
+ end
301
+
302
+ if headers == nil
303
+ headers = {
304
+ :content_type => :json
305
+ }
306
+ else
307
+ headers[:content_type] = :json
308
+ end
309
+
310
+ unless auth_token == nil
311
+ headers[:authorization] = 'Bearer ' + auth_token
312
+ end
313
+
314
+ if endpoint.expect_json
315
+ headers[:accept] = :json
316
+ end
317
+
318
+ response = block.call(env, url, data, headers)
319
+ rescue Errno::ECONNREFUSED
320
+ response = { :error => 'Unable to connect to host ' + env.host.to_s + ':' + env.port.to_s }.to_json
321
+ end
322
+
323
+ unless endpoint.expect_json or endpoint.method != :head
324
+ return response
325
+ end
326
+
327
+ JSON.parse(response, object_class: OpenStruct)
328
+ end
123
329
  end
124
330
  end
@@ -2,16 +2,17 @@ require 'addressable/template'
2
2
 
3
3
  module Bubbles
4
4
  class RestEnvironment
5
- attr_accessor :scheme, :host, :port
5
+ attr_accessor :scheme, :host, :port, :api_key
6
6
 
7
7
  ##
8
8
  # Construct a new instance of +RestEnvironment+.
9
9
  #
10
- # @param scheme The scheme to use for communicating with the host. Currently, http and https are supported.
11
- # @param host The host to communicate with.
12
- # @param port The port on which the communication channel should operate.
10
+ # @param [String] scheme The scheme to use for communicating with the host. Currently, http and https are supported.
11
+ # @param [String] host The host to communicate with.
12
+ # @param [Integer] port The port on which the communication channel should operate.
13
+ # @param [String] api_key (Optional) The API key to use to identify your client with the API. Defaults to +nil+.
13
14
  #
14
- def initialize(scheme='https', host='api.foamfactory.com', port=443)
15
+ def initialize(scheme='https', host='api.foamfactory.com', port=443, api_key=nil)
15
16
  @scheme = scheme
16
17
  @port = port
17
18
 
@@ -20,49 +21,7 @@ module Bubbles
20
21
  end
21
22
 
22
23
  @host = host
24
+ @api_key = api_key
23
25
  end
24
-
25
- ##
26
- # Add an unauthenticated endpoint to this +RestEnvironment+.
27
- #
28
- # @param type The type of the endpoint. Must be one of [:get].
29
- # @param endpoint The path to the endpoint, without the leading slash.
30
- #
31
- # def add_unauthenticated_endpoint(type, endpoint)
32
- # if type == :get
33
- # unless endpoint.include? "/"
34
- # @endpoints[endpoint] = get_url.expand(scheme: @scheme, environment_host: @host, port: @port, endpoint: endpoint).to_s
35
- # return
36
- # end
37
- #
38
- # @endpoints[endpoint] = get_url_with_special_endpoint.expand(scheme: @scheme, environment_host: @host, port: @port, endpoint: endpoint).to_s
39
- # end
40
- # end
41
-
42
- # def get_endpoint_string(endpoint)
43
- # @endpoints[endpoint]
44
- # end
45
-
46
- def get_base_url
47
-
48
- end
49
-
50
- private
51
- ##
52
- # Get an addressable template for a 'special' endpoint (one containing '/' characters)
53
- #
54
- # @param endpoint The endpoint to get an addressable URL to.
55
- #
56
- # @returns The ::Addressable::Template without the endpoint parameter encoded in the URI.
57
- #
58
- # def get_url_with_special_endpoint(endpoint)
59
- # special_url_string = '{scheme}://{environment_host}/'
60
- # unless @port == 80 || @port == 443
61
- # special_url_string = '{scheme}://{environment_host}:{port}/'
62
- # end
63
- #
64
- # special_url_string = special_url_string + endpoint
65
- # ::Addressable::Template.new(special_url_string)
66
- # end
67
26
  end
68
27
  end
@@ -5,7 +5,7 @@ module Bubbles
5
5
  end
6
6
 
7
7
  def self.version_name
8
- '0.0.8'
8
+ '0.1.0'
9
9
  end
10
10
 
11
11
  def self.version_code
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bubbles-rest-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Johnson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-19 00:00:00.000000000 Z
11
+ date: 2019-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -165,15 +165,13 @@ files:
165
165
  - README.md
166
166
  - Rakefile
167
167
  - bubbles.gemspec
168
- - fixtures/vcr_cassettes/get_students_authenticated.yml
169
- - fixtures/vcr_cassettes/get_version_unauthenticated.yml
170
168
  - lib/bubbles.rb
171
169
  - lib/bubbles/config.rb
172
170
  - lib/bubbles/endpoint.rb
173
171
  - lib/bubbles/rest_client_resources.rb
174
172
  - lib/bubbles/rest_environment.rb
175
173
  - lib/bubbles/version.rb
176
- homepage: http://www.foamfactorybrewing.com
174
+ homepage: https://github.com/FoamFactory/bubbles
177
175
  licenses:
178
176
  - MPL-2.0
179
177
  metadata:
@@ -1,46 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: get
5
- uri: http://127.0.0.1:1234/students
6
- body:
7
- encoding: US-ASCII
8
- string: ''
9
- headers:
10
- Accept:
11
- - "*/*"
12
- Accept-Encoding:
13
- - gzip, deflate
14
- User-Agent:
15
- - rest-client/2.0.2 (darwin16.1.0 x86_64) ruby/2.4.0p0
16
- Authorization:
17
- - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjcmVhdGlvbl9kYXRlIjoiMjAxNy0xMC0xNVQxMToyNjozMS0wNTowMCIsImV4cGlyYXRpb25fZGF0ZSI6IjIwMTctMTEtMTRUMTE6MjY6MzEtMDU6MDAiLCJ1c2VyX2lkIjoxfQ.dyCWwE4wk7aTfjnGncsqp_jq5QyICKYQPkBh5nLQwFU
18
- Content-Type:
19
- - application/json
20
- Host:
21
- - 127.0.0.1:1234
22
- response:
23
- status:
24
- code: 200
25
- message: OK
26
- headers:
27
- Content-Type:
28
- - application/json; charset=utf-8
29
- Etag:
30
- - W/"9d4b7d98d38caa096dee4e7844662cf6"
31
- Cache-Control:
32
- - max-age=0, private, must-revalidate
33
- X-Request-Id:
34
- - de8e2f1a-4eb7-44a5-9129-84df77d3b938
35
- X-Runtime:
36
- - '0.014508'
37
- Transfer-Encoding:
38
- - chunked
39
- body:
40
- encoding: UTF-8
41
- string: '{"students":[{"id":1,"name":"Joe Blow","address":"2234 Bubble Gum Ave.
42
- #127","city":"Sometown","state":"CA","zip":"90263","phone":"5558764566","email":"bubblegumbanshee987@bazooka.org","emergencyContactName":"Some
43
- Guy","emergencyContactPhone":"5554339182","joinDate":"2017-10-14T00:00:00.000Z","lastAdvancementDate":"2017-10-14T00:00:00.000Z","waiverSigned":true,"created_at":"2017-10-14T21:46:42.826Z","updated_at":"2017-10-14T21:46:42.826Z","preferredContact":"phone","rank":"green"}]}'
44
- http_version:
45
- recorded_at: Sun, 15 Oct 2017 16:51:12 GMT
46
- recorded_with: VCR 3.0.3
@@ -1,42 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: get
5
- uri: http://127.0.0.1:1234/version
6
- body:
7
- encoding: US-ASCII
8
- string: ''
9
- headers:
10
- Accept:
11
- - "*/*"
12
- Accept-Encoding:
13
- - gzip, deflate
14
- User-Agent:
15
- - rest-client/2.0.2 (darwin16.1.0 x86_64) ruby/2.4.0p0
16
- Content-Type:
17
- - application/json
18
- Host:
19
- - 127.0.0.1:1234
20
- response:
21
- status:
22
- code: 200
23
- message: OK
24
- headers:
25
- Content-Type:
26
- - application/json; charset=utf-8
27
- Etag:
28
- - W/"939eb8a8e26be1cdc231493379b6d17c"
29
- Cache-Control:
30
- - max-age=0, private, must-revalidate
31
- X-Request-Id:
32
- - fab0bd54-b471-46d4-8f1f-9165c1549c8f
33
- X-Runtime:
34
- - '0.263693'
35
- Transfer-Encoding:
36
- - chunked
37
- body:
38
- encoding: UTF-8
39
- string: '{"name":"Sinking Moon API","versionName":"2.0.0","versionCode":8,"deployDate":"2018-01-02T22:51:29-06:00"}'
40
- http_version:
41
- recorded_at: Wed, 03 Jan 2018 04:51:29 GMT
42
- recorded_with: VCR 3.0.3