bootic_client 0.0.21 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +25 -0
- data/Gemfile +1 -1
- data/README.md +43 -0
- data/lib/bootic_client/client.rb +1 -2
- data/lib/bootic_client/configuration.rb +74 -0
- data/lib/bootic_client/entity.rb +4 -5
- data/lib/bootic_client/relation.rb +5 -5
- data/lib/bootic_client/response_handlers.rb +61 -0
- data/lib/bootic_client/strategies/authorized.rb +2 -2
- data/lib/bootic_client/strategies/basic_auth.rb +3 -3
- data/lib/bootic_client/strategies/bearer.rb +1 -1
- data/lib/bootic_client/strategies/client_credentials.rb +1 -1
- data/lib/bootic_client/strategies/oauth2_strategy.rb +4 -4
- data/lib/bootic_client/strategies/strategy.rb +7 -5
- data/lib/bootic_client/version.rb +1 -1
- data/lib/bootic_client.rb +9 -64
- data/spec/authorized_strategy_spec.rb +5 -4
- data/spec/basic_auth_strategy_spec.rb +10 -6
- data/spec/bearer_strategy_spec.rb +4 -3
- data/spec/client_credentials_strategy_spec.rb +3 -2
- data/spec/client_spec.rb +19 -16
- data/spec/configuration_spec.rb +62 -50
- data/spec/entity_spec.rb +9 -5
- data/spec/relation_spec.rb +8 -8
- data/spec/response_handlers_spec.rb +73 -0
- data/spec/strategy_spec.rb +73 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 30679ee6a43b99369706f814812e081c631f7fb430ee1aee257f39690dd065bd
|
4
|
+
data.tar.gz: 5edc48fe9a7f34e4adb0cd2eeab702953b7371d29ff538fb7a2c629ebd74d29c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7177b27e419870b4e158b717f94d5a5209748c9f2d8ca590bfeec21acfaef677feabd50d70a9a67f669c4679400be9b10937e21db6114d606fa4338e289b737
|
7
|
+
data.tar.gz: 034fa3444247619b836be72220d1009ff407a53e5b5551eb5faa127196aa0dfa5a908c7697ba24f2f881150c5e0eb7d5b3410295c5a93a2493abe611ab690a64
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [Unreleased](https://github.com/bootic/bootic_client.rb/tree/HEAD)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bootic/bootic_client.rb/compare/v0.0.21...HEAD)
|
6
|
+
|
7
|
+
**Merged pull requests:**
|
8
|
+
|
9
|
+
- Custom response handlers [\#18](https://github.com/bootic/bootic_client.rb/pull/18) ([ismasan](https://github.com/ismasan))
|
10
|
+
- Wrap all hash properties in Entity.new, even if not in \_embedded group. [\#17](https://github.com/bootic/bootic_client.rb/pull/17) ([ismasan](https://github.com/ismasan))
|
11
|
+
- Make configuration an instance [\#16](https://github.com/bootic/bootic_client.rb/pull/16) ([ismasan](https://github.com/ismasan))
|
12
|
+
|
13
|
+
## [v0.0.21](https://github.com/bootic/bootic_client.rb/tree/v0.0.21) (2018-08-30)
|
14
|
+
[Full Changelog](https://github.com/bootic/bootic_client.rb/compare/v0.0.20...v0.0.21)
|
15
|
+
|
16
|
+
**Merged pull requests:**
|
17
|
+
|
18
|
+
- Add :user\_agent option [\#13](https://github.com/bootic/bootic_client.rb/pull/13) ([ismasan](https://github.com/ismasan))
|
19
|
+
|
20
|
+
## [v0.0.20](https://github.com/bootic/bootic_client.rb/tree/v0.0.20) (2018-07-05)
|
21
|
+
[Full Changelog](https://github.com/bootic/bootic_client.rb/compare/v0.0.19...v0.0.20)
|
22
|
+
|
23
|
+
**Merged pull requests:**
|
24
|
+
|
25
|
+
- Validate config setters [\#15](https://github.com/bootic/bootic_client.rb/pull/15) ([ismasan](https://github.com/ismasan))
|
26
|
+
- Whitelist undeclared params [\#12](https://github.com/bootic/bootic_client.rb/pull/12) ([ismasan](https://github.com/ismasan))
|
27
|
+
|
3
28
|
## [v0.0.19](https://github.com/bootic/bootic_client.rb/tree/v0.0.19) (2017-06-01)
|
4
29
|
[Full Changelog](https://github.com/bootic/bootic_client.rb/compare/v0.0.18...v0.0.19)
|
5
30
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -218,6 +218,49 @@ asset = product.create_product_asset(
|
|
218
218
|
)
|
219
219
|
```
|
220
220
|
|
221
|
+
## Non-JSON responses
|
222
|
+
|
223
|
+
HTTP responses are resolved by handler callables in `BooticClient::Configuration#response_handlers`.
|
224
|
+
|
225
|
+
The default stack is:
|
226
|
+
|
227
|
+
* `BooticClient::ResponseHandlers::Hal`: handles `application/json` responses and wraps JSON data in `BooticClient::Entity` instances.
|
228
|
+
* `BooticClient::ResponseHandlers::File`: handles `image/*` responses and wraps image data in IO-like objects.
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
# Fetching product images and saving them to local files:
|
232
|
+
product.images.each do |img|
|
233
|
+
io = img.original # HTTP request to image file
|
234
|
+
# now write image data to local file.
|
235
|
+
File.open(io.file_name, 'wb') do |f|
|
236
|
+
f.write io.read
|
237
|
+
end
|
238
|
+
end
|
239
|
+
```
|
240
|
+
|
241
|
+
You can register custom response handlers. The example below parses CSV response data.
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
require 'csv'
|
245
|
+
|
246
|
+
# Response handlers are callable (anything that responds to #call(faraday_response, client)
|
247
|
+
# if a handler returns `nil`, the next handler in the stack will be called.
|
248
|
+
CSVHandler = Proc.new do |resp, _client|
|
249
|
+
if resp.headers['Content-Type'] =~ /text\/csv/
|
250
|
+
CSV.parse(resp.body, headings: true)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
BooticClient.configure do |c|
|
255
|
+
c.response_handlers.append(CSVHandler)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Now CSV resources will be returned as parsed CSV data
|
259
|
+
client = BooticClient.client(:authorized, access_token: 'abc')
|
260
|
+
root = client.root
|
261
|
+
csv = root.some_csv_resource # returns parsed CSV object.
|
262
|
+
```
|
263
|
+
|
221
264
|
## Relation docs
|
222
265
|
|
223
266
|
All resource link relations include a "docs" URL so you can learn more about that particular resource.
|
data/lib/bootic_client/client.rb
CHANGED
@@ -60,7 +60,7 @@ module BooticClient
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
private
|
64
64
|
|
65
65
|
def conn(&block)
|
66
66
|
@conn ||= Faraday.new do |f|
|
@@ -69,7 +69,6 @@ module BooticClient
|
|
69
69
|
|
70
70
|
f.use :http_cache, cache_options
|
71
71
|
f.response :logger, options[:logger] if options[:logging]
|
72
|
-
f.response :json
|
73
72
|
yield f if block_given?
|
74
73
|
f.adapter *Array(options[:faraday_adapter])
|
75
74
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'bootic_client/response_handlers'
|
2
|
+
|
3
|
+
module BooticClient
|
4
|
+
InvalidConfigurationError = Class.new(StandardError)
|
5
|
+
VERY_BASIC_URL_CHECK = /^(http|https):/.freeze
|
6
|
+
|
7
|
+
AUTH_HOST = 'https://auth.bootic.net'.freeze
|
8
|
+
API_ROOT = 'https://api.bootic.net/v1'.freeze
|
9
|
+
|
10
|
+
class Configuration
|
11
|
+
attr_accessor :logging
|
12
|
+
attr_reader :client_id, :client_secret, :cache_store, :user_agent
|
13
|
+
|
14
|
+
def user_agent=(v)
|
15
|
+
set_non_nil :user_agent, v
|
16
|
+
end
|
17
|
+
|
18
|
+
def client_id=(v)
|
19
|
+
set_non_nil :client_id, v
|
20
|
+
end
|
21
|
+
|
22
|
+
def client_secret=(v)
|
23
|
+
set_non_nil :client_secret, v
|
24
|
+
end
|
25
|
+
|
26
|
+
def cache_store=(v)
|
27
|
+
set_non_nil :cache_store, v
|
28
|
+
end
|
29
|
+
|
30
|
+
def auth_host=(v)
|
31
|
+
check_url! :auth_host, v
|
32
|
+
set_non_nil :auth_host, v
|
33
|
+
end
|
34
|
+
|
35
|
+
def api_root=(v)
|
36
|
+
check_url! :api_root, v
|
37
|
+
set_non_nil :api_root, v
|
38
|
+
end
|
39
|
+
|
40
|
+
def logger=(v)
|
41
|
+
set_non_nil :logger, v
|
42
|
+
end
|
43
|
+
|
44
|
+
def auth_host
|
45
|
+
@auth_host || AUTH_HOST
|
46
|
+
end
|
47
|
+
|
48
|
+
def api_root
|
49
|
+
@api_root || API_ROOT
|
50
|
+
end
|
51
|
+
|
52
|
+
def logger
|
53
|
+
@logger || ::Logger.new(STDOUT)
|
54
|
+
end
|
55
|
+
|
56
|
+
def response_handlers
|
57
|
+
@response_handlers ||= ResponseHandlers::Set.new([
|
58
|
+
ResponseHandlers::Hal,
|
59
|
+
ResponseHandlers::File
|
60
|
+
])
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def set_non_nil(name, v)
|
66
|
+
raise InvalidConfigurationError, "#{name} cannot be nil" if v.nil?
|
67
|
+
instance_variable_set("@#{name}", v)
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_url!(name, v)
|
71
|
+
raise InvalidConfigurationError, "#{name} must be a valid URL" unless v.to_s =~ VERY_BASIC_URL_CHECK
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/bootic_client/entity.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require "bootic_client/relation"
|
2
|
-
require 'ostruct'
|
3
2
|
|
4
3
|
module BooticClient
|
5
4
|
module EnumerableEntity
|
@@ -60,7 +59,7 @@ module BooticClient
|
|
60
59
|
|
61
60
|
def properties
|
62
61
|
@properties ||= attrs.select{|k,v| !(k =~ SPECIAL_PROP_EXP)}.each_with_object({}) do |(k,v),memo|
|
63
|
-
memo[k.to_sym] = Entity.wrap(v)
|
62
|
+
memo[k.to_sym] = Entity.wrap(v, client: client, top: top)
|
64
63
|
end
|
65
64
|
end
|
66
65
|
|
@@ -68,10 +67,10 @@ module BooticClient
|
|
68
67
|
@links ||= attrs.fetch('_links', {})
|
69
68
|
end
|
70
69
|
|
71
|
-
def self.wrap(obj)
|
70
|
+
def self.wrap(obj, client: nil, top: nil)
|
72
71
|
case obj
|
73
72
|
when Hash
|
74
|
-
|
73
|
+
new(obj, client, top: top)
|
75
74
|
when Array
|
76
75
|
obj.map{|e| wrap(e)}
|
77
76
|
else
|
@@ -129,7 +128,7 @@ module BooticClient
|
|
129
128
|
)
|
130
129
|
end
|
131
130
|
|
132
|
-
|
131
|
+
private
|
133
132
|
|
134
133
|
attr_reader :client, :top, :attrs
|
135
134
|
|
@@ -18,8 +18,8 @@ module BooticClient
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def initialize(attrs, client,
|
22
|
-
@attrs, @client
|
21
|
+
def initialize(attrs, client, complain_on_undeclared_params: self.class.complain_on_undeclared_params)
|
22
|
+
@attrs, @client = attrs, client
|
23
23
|
@complain_on_undeclared_params = complain_on_undeclared_params
|
24
24
|
end
|
25
25
|
|
@@ -71,9 +71,9 @@ module BooticClient
|
|
71
71
|
end
|
72
72
|
# remove payload vars from URI opts if destructive action
|
73
73
|
opts = opts.reject{|k, v| !uri_vars.include?(k.to_s) } if destructive?
|
74
|
-
client.request_and_wrap transport_method.to_sym, uri.expand(opts),
|
74
|
+
client.request_and_wrap transport_method.to_sym, uri.expand(opts), payload
|
75
75
|
else
|
76
|
-
client.request_and_wrap transport_method.to_sym, href,
|
76
|
+
client.request_and_wrap transport_method.to_sym, href, opts
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
@@ -82,7 +82,7 @@ module BooticClient
|
|
82
82
|
end
|
83
83
|
|
84
84
|
protected
|
85
|
-
attr_reader :
|
85
|
+
attr_reader :client, :attrs, :complain_on_undeclared_params
|
86
86
|
|
87
87
|
def uri
|
88
88
|
@uri ||= WhinyURI.new(href, complain_on_undeclared_params)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module BooticClient
|
4
|
+
module ResponseHandlers
|
5
|
+
class Set
|
6
|
+
def initialize(handlers = [])
|
7
|
+
@handlers = handlers
|
8
|
+
end
|
9
|
+
|
10
|
+
def resolve(response, client)
|
11
|
+
custom = @handlers.find do |handler|
|
12
|
+
obj = handler.call(response, client)
|
13
|
+
break obj if obj
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
# if no handler found,
|
17
|
+
# return raw Faraday response
|
18
|
+
custom || response
|
19
|
+
end
|
20
|
+
|
21
|
+
def append(handler)
|
22
|
+
@handlers << handler
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepend(handler)
|
26
|
+
@handlers.unshift handler
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_a
|
30
|
+
@handlers
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
JSON_MIME_EXP = /^application\/json/.freeze
|
35
|
+
IMAGE_MIME_EXP = /^image\//.freeze
|
36
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
37
|
+
IO = Struct.new(:io, :file_name, :mime_type) do
|
38
|
+
def read
|
39
|
+
io.read
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Hal = Proc.new do |resp, client|
|
44
|
+
if resp.headers[CONTENT_TYPE] =~ JSON_MIME_EXP
|
45
|
+
data = ::JSON.parse(resp.body)
|
46
|
+
Entity.new(data, client)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
File = Proc.new do |resp, client|
|
51
|
+
if resp.headers[CONTENT_TYPE] =~ IMAGE_MIME_EXP
|
52
|
+
fname = ::File.basename(resp.env[:url].to_s)
|
53
|
+
IO.new(
|
54
|
+
StringIO.new(resp.body),
|
55
|
+
fname,
|
56
|
+
resp.headers[CONTENT_TYPE]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -4,10 +4,10 @@ module BooticClient
|
|
4
4
|
module Strategies
|
5
5
|
|
6
6
|
class Authorized < Oauth2Strategy
|
7
|
-
|
7
|
+
private
|
8
8
|
|
9
9
|
def validate!
|
10
|
-
raise ArgumentError,
|
10
|
+
raise ArgumentError, 'options MUST include access_token' unless options[:access_token]
|
11
11
|
end
|
12
12
|
|
13
13
|
def get_token
|
@@ -8,11 +8,11 @@ module BooticClient
|
|
8
8
|
%(#<#{self.class.name} root: #{config.api_root} username: #{options[:username]}>)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
private
|
12
12
|
|
13
13
|
def validate!
|
14
|
-
raise ArgumentError,
|
15
|
-
raise ArgumentError,
|
14
|
+
raise ArgumentError, 'options MUST include username' unless options[:username]
|
15
|
+
raise ArgumentError, 'options MUST include password' unless options[:password]
|
16
16
|
end
|
17
17
|
|
18
18
|
def client
|
@@ -10,12 +10,12 @@ module BooticClient
|
|
10
10
|
%(#<#{self.class.name} cid: #{config.client_id} root: #{config.api_root} auth: #{config.auth_host}>)
|
11
11
|
end
|
12
12
|
|
13
|
-
|
13
|
+
private
|
14
14
|
|
15
15
|
def validate!
|
16
|
-
raise ArgumentError,
|
17
|
-
raise ArgumentError,
|
18
|
-
raise ArgumentError,
|
16
|
+
raise ArgumentError, 'MUST include client_id' unless config.client_id
|
17
|
+
raise ArgumentError, 'MUST include client_secret' unless config.client_secret
|
18
|
+
raise ArgumentError, 'MUST include api_root' unless config.api_root
|
19
19
|
end
|
20
20
|
|
21
21
|
def pre_flight
|
@@ -6,25 +6,27 @@ module BooticClient
|
|
6
6
|
|
7
7
|
def initialize(config, client_opts = {}, &on_new_token)
|
8
8
|
@config, @options, @on_new_token = config, client_opts, (on_new_token || Proc.new{})
|
9
|
+
raise ArgumentError, 'must include a Configuration object' unless config
|
9
10
|
validate!
|
10
11
|
end
|
11
12
|
|
12
13
|
def root
|
13
|
-
request_and_wrap :get, config.api_root
|
14
|
+
request_and_wrap :get, config.api_root
|
14
15
|
end
|
15
16
|
|
16
17
|
def from_hash(hash, wrapper_class = Entity)
|
17
18
|
wrapper_class.new hash, self
|
18
19
|
end
|
19
20
|
|
20
|
-
def from_url(url
|
21
|
-
request_and_wrap :get, url
|
21
|
+
def from_url(url)
|
22
|
+
request_and_wrap :get, url
|
22
23
|
end
|
23
24
|
|
24
|
-
def request_and_wrap(request_method, href,
|
25
|
+
def request_and_wrap(request_method, href, payload = {})
|
25
26
|
pre_flight
|
26
27
|
retryable do
|
27
|
-
|
28
|
+
resp = client.send(request_method, href, payload, request_headers)
|
29
|
+
config.response_handlers.resolve(resp, self)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
data/lib/bootic_client.rb
CHANGED
@@ -3,85 +3,30 @@ require "bootic_client/version"
|
|
3
3
|
require "bootic_client/entity"
|
4
4
|
require "bootic_client/relation"
|
5
5
|
require "bootic_client/client"
|
6
|
+
require "bootic_client/configuration"
|
6
7
|
|
7
8
|
module BooticClient
|
8
|
-
InvalidConfigurationError = Class.new(StandardError)
|
9
|
-
VERY_BASIC_URL_CHECK = /^(http|https):/.freeze
|
10
|
-
|
11
|
-
AUTH_HOST = 'https://auth.bootic.net'.freeze
|
12
|
-
API_ROOT = 'https://api.bootic.net/v1'.freeze
|
13
|
-
|
14
9
|
class << self
|
15
|
-
attr_accessor :logging
|
16
|
-
attr_reader :client_id, :client_secret, :cache_store, :user_agent
|
17
|
-
|
18
10
|
def strategies
|
19
11
|
@strategies ||= {}
|
20
12
|
end
|
21
13
|
|
22
14
|
def client(strategy_name, client_opts = {}, &on_new_token)
|
23
15
|
opts = client_opts.dup
|
24
|
-
opts[:logging] = logging
|
25
|
-
opts[:logger] = logger if logging
|
26
|
-
opts[:cache_store] = cache_store if cache_store
|
27
|
-
opts[:user_agent] = user_agent if user_agent
|
16
|
+
opts[:logging] = configuration.logging
|
17
|
+
opts[:logger] = configuration.logger if configuration.logging
|
18
|
+
opts[:cache_store] = configuration.cache_store if configuration.cache_store
|
19
|
+
opts[:user_agent] = configuration.user_agent if configuration.user_agent
|
28
20
|
require "bootic_client/strategies/#{strategy_name}"
|
29
|
-
strategies.fetch(strategy_name.to_sym).new
|
30
|
-
end
|
31
|
-
|
32
|
-
def user_agent=(v)
|
33
|
-
set_non_nil :user_agent, v
|
34
|
-
end
|
35
|
-
|
36
|
-
def client_id=(v)
|
37
|
-
set_non_nil :client_id, v
|
38
|
-
end
|
39
|
-
|
40
|
-
def client_secret=(v)
|
41
|
-
set_non_nil :client_secret, v
|
42
|
-
end
|
43
|
-
|
44
|
-
def cache_store=(v)
|
45
|
-
set_non_nil :cache_store, v
|
46
|
-
end
|
47
|
-
|
48
|
-
def auth_host=(v)
|
49
|
-
check_url! :auth_host, v
|
50
|
-
set_non_nil :auth_host, v
|
51
|
-
end
|
52
|
-
|
53
|
-
def api_root=(v)
|
54
|
-
check_url! :api_root, v
|
55
|
-
set_non_nil :api_root, v
|
56
|
-
end
|
57
|
-
|
58
|
-
def logger=(v)
|
59
|
-
set_non_nil :logger, v
|
60
|
-
end
|
61
|
-
|
62
|
-
def auth_host
|
63
|
-
@auth_host || AUTH_HOST
|
64
|
-
end
|
65
|
-
|
66
|
-
def api_root
|
67
|
-
@api_root || API_ROOT
|
68
|
-
end
|
69
|
-
|
70
|
-
def logger
|
71
|
-
@logger || ::Logger.new(STDOUT)
|
21
|
+
strategies.fetch(strategy_name.to_sym).new configuration, opts, &on_new_token
|
72
22
|
end
|
73
23
|
|
74
24
|
def configure(&block)
|
75
|
-
yield
|
76
|
-
end
|
77
|
-
|
78
|
-
def set_non_nil(name, v)
|
79
|
-
raise InvalidConfigurationError, "#{name} cannot be nil" if v.nil?
|
80
|
-
instance_variable_set("@#{name}", v)
|
25
|
+
yield configuration
|
81
26
|
end
|
82
27
|
|
83
|
-
def
|
84
|
-
|
28
|
+
def configuration
|
29
|
+
@configuration ||= Configuration.new
|
85
30
|
end
|
86
31
|
end
|
87
32
|
end
|
@@ -6,6 +6,7 @@ describe 'BooticClient::Strategies::Authorized' do
|
|
6
6
|
|
7
7
|
let(:client_id) {'aaa'}
|
8
8
|
let(:client_secret) {'bbb'}
|
9
|
+
let(:response_headers) { {'Content-Type' => 'application/json'} }
|
9
10
|
|
10
11
|
def jwt_assertion(expired_token, now)
|
11
12
|
JWT.encode({
|
@@ -19,7 +20,7 @@ describe 'BooticClient::Strategies::Authorized' do
|
|
19
20
|
def stub_api_root(access_token, status, body)
|
20
21
|
stub_request(:get, "https://api.bootic.net/v1").
|
21
22
|
with(headers: {'Accept'=>'application/json', 'Authorization' => "Bearer #{access_token}"}).
|
22
|
-
to_return(status: status, :body => JSON.dump(body))
|
23
|
+
to_return(status: status, :headers => response_headers, :body => JSON.dump(body))
|
23
24
|
end
|
24
25
|
|
25
26
|
def stub_auth(expired_token, status, body, client_id: '', client_secret: '', scope: '')
|
@@ -127,12 +128,12 @@ describe 'BooticClient::Strategies::Authorized' do
|
|
127
128
|
stub_api_root('abc', 200, root_data)
|
128
129
|
@unauthorized_request = stub_request(:get, "https://api.bootic.net/v1/shops").
|
129
130
|
with(headers: {'Accept'=>'application/json', 'Authorization' => "Bearer abc"}).
|
130
|
-
to_return(status: 401, :body => JSON.dump(message: 'authorized'))
|
131
|
+
to_return(status: 401, headers: response_headers, :body => JSON.dump(message: 'authorized'))
|
131
132
|
@auth_request = stub_auth('abc', 200, access_token: 'validtoken')
|
132
133
|
|
133
134
|
@authorized_request = stub_request(:get, "https://api.bootic.net/v1/shops").
|
134
135
|
with(headers: {'Accept'=>'application/json', 'Authorization' => "Bearer validtoken"}).
|
135
|
-
to_return(status: 200, :body => JSON.dump(title: 'All shops'))
|
136
|
+
to_return(status: 200, headers: response_headers, :body => JSON.dump(title: 'All shops'))
|
136
137
|
@root = client.root
|
137
138
|
end
|
138
139
|
|
@@ -157,7 +158,7 @@ describe 'BooticClient::Strategies::Authorized' do
|
|
157
158
|
describe '#from_url' do
|
158
159
|
it 'builds and returns an entity' do
|
159
160
|
authorized_request = stub_request(:get, "https://api.bootic.net/v1/shops").
|
160
|
-
to_return(status: 200, :body => JSON.dump(title: 'All shops'))
|
161
|
+
to_return(status: 200, headers: response_headers, :body => JSON.dump(title: 'All shops'))
|
161
162
|
|
162
163
|
entity = client.from_url('https://api.bootic.net/v1/shops')
|
163
164
|
expect(entity).to be_kind_of(BooticClient::Entity)
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe 'BooticClient::Strategies::BasicAuth' do
|
4
4
|
require 'webmock/rspec'
|
5
5
|
|
6
|
+
let(:response_headers) { {'Content-Type' => 'application/json'} }
|
6
7
|
let(:root_data) {
|
7
8
|
{
|
8
9
|
'_links' => {
|
@@ -34,8 +35,9 @@ describe 'BooticClient::Strategies::BasicAuth' do
|
|
34
35
|
|
35
36
|
context 'with invalid BasicAuth credentials' do
|
36
37
|
let!(:root_request) do
|
37
|
-
stub_request(:get, 'https://
|
38
|
-
.
|
38
|
+
stub_request(:get, 'https://api.bootic.net/v1')
|
39
|
+
.with(basic_auth: ['foo', 'bar'])
|
40
|
+
.to_return(status: 401, headers: response_headers, body: JSON.dump(root_data))
|
39
41
|
end
|
40
42
|
|
41
43
|
it 'raises an Unauthorized error' do
|
@@ -46,13 +48,15 @@ describe 'BooticClient::Strategies::BasicAuth' do
|
|
46
48
|
|
47
49
|
context 'with valid BasicAuth credentials' do
|
48
50
|
let!(:root_request) do
|
49
|
-
stub_request(:get, 'https://
|
50
|
-
.
|
51
|
+
stub_request(:get, 'https://api.bootic.net/v1')
|
52
|
+
.with(basic_auth: ['foo', 'bar'])
|
53
|
+
.to_return(status: 200, headers: response_headers, body: JSON.dump(root_data))
|
51
54
|
end
|
52
55
|
|
53
56
|
let!(:product_request) do
|
54
|
-
stub_request(:get, 'https://
|
55
|
-
.
|
57
|
+
stub_request(:get, 'https://api.bootic.net/v1/products/1')
|
58
|
+
.with(basic_auth: ['foo', 'bar'])
|
59
|
+
.to_return(status: 200, headers: response_headers, body: JSON.dump(product_data))
|
56
60
|
end
|
57
61
|
|
58
62
|
let!(:root) { client.root }
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe 'BooticClient::Strategies::Bearer' do
|
4
4
|
require 'webmock/rspec'
|
5
5
|
|
6
|
+
let(:response_headers) { {'Content-Type' => 'application/json'} }
|
6
7
|
let(:root_data) {
|
7
8
|
{
|
8
9
|
'_links' => {
|
@@ -36,7 +37,7 @@ describe 'BooticClient::Strategies::Bearer' do
|
|
36
37
|
let!(:root_request) do
|
37
38
|
stub_request(:get, 'https://api.bootic.net/v1')
|
38
39
|
.with(headers: {"Authorization" => "Bearer foobar"})
|
39
|
-
.to_return(status: 401, body: JSON.dump(root_data))
|
40
|
+
.to_return(status: 401, headers: response_headers, body: JSON.dump(root_data))
|
40
41
|
end
|
41
42
|
|
42
43
|
it 'raises an Unauthorized error' do
|
@@ -49,13 +50,13 @@ describe 'BooticClient::Strategies::Bearer' do
|
|
49
50
|
let!(:root_request) do
|
50
51
|
stub_request(:get, 'https://api.bootic.net/v1')
|
51
52
|
.with(headers: {"Authorization" => "Bearer foobar"})
|
52
|
-
.to_return(status: 200, body: JSON.dump(root_data))
|
53
|
+
.to_return(status: 200, headers: response_headers, body: JSON.dump(root_data))
|
53
54
|
end
|
54
55
|
|
55
56
|
let!(:product_request) do
|
56
57
|
stub_request(:get, 'https://api.bootic.net/v1/products/1')
|
57
58
|
.with(headers: {"Authorization" => "Bearer foobar"})
|
58
|
-
.to_return(status: 200, body: JSON.dump(product_data))
|
59
|
+
.to_return(status: 200, headers: response_headers, body: JSON.dump(product_data))
|
59
60
|
end
|
60
61
|
|
61
62
|
let!(:root) { client.root }
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe 'BooticClient::Strategies::ClientCredentials' do
|
4
4
|
require 'webmock/rspec'
|
5
5
|
|
6
|
+
let(:response_headers) { {'Content-Type' => 'application/json'} }
|
6
7
|
let(:store){ Hash.new }
|
7
8
|
let(:root_data) {
|
8
9
|
{
|
@@ -15,7 +16,7 @@ describe 'BooticClient::Strategies::ClientCredentials' do
|
|
15
16
|
|
16
17
|
describe 'with missing client credentials' do
|
17
18
|
it 'raises error' do
|
18
|
-
allow(BooticClient).to receive(:client_id).and_return nil
|
19
|
+
allow(BooticClient.configuration).to receive(:client_id).and_return nil
|
19
20
|
expect{
|
20
21
|
BooticClient.client(:client_credentials, scope: 'admin')
|
21
22
|
}.to raise_error(ArgumentError)
|
@@ -33,7 +34,7 @@ describe 'BooticClient::Strategies::ClientCredentials' do
|
|
33
34
|
def stub_api_root(access_token, status, body)
|
34
35
|
stub_request(:get, "https://api.bootic.net/v1").
|
35
36
|
with(headers: {'Accept'=>'application/json', 'Authorization'=>"Bearer #{access_token}"}).
|
36
|
-
to_return(status: status, body: JSON.dump(body))
|
37
|
+
to_return(status: status, headers: response_headers, body: JSON.dump(body))
|
37
38
|
end
|
38
39
|
|
39
40
|
before do
|
data/spec/client_spec.rb
CHANGED
@@ -37,9 +37,7 @@ describe BooticClient::Client do
|
|
37
37
|
def assert_successful_response(response)
|
38
38
|
expect(response).to be_kind_of(Faraday::Response)
|
39
39
|
expect(response.status).to eql(200)
|
40
|
-
response.body.
|
41
|
-
expect(b['_links']['shops']).to eql({'href' => 'https://api.bootic.net/v1/products'})
|
42
|
-
end
|
40
|
+
expect(response.body).not_to be nil
|
43
41
|
end
|
44
42
|
|
45
43
|
context 'switching cache key as per Vary header' do
|
@@ -193,11 +191,11 @@ describe BooticClient::Client do
|
|
193
191
|
before do
|
194
192
|
stub_request(:get, root_url)
|
195
193
|
.with(query: {foo: 'bar'}, headers: request_headers)
|
196
|
-
.to_return(status: 200, body:
|
194
|
+
.to_return(status: 200, body: 'abc')
|
197
195
|
end
|
198
196
|
|
199
197
|
it 'GETs response' do
|
200
|
-
expect(client.get(root_url, {foo: 'bar'}, request_headers).body
|
198
|
+
expect(client.get(root_url, {foo: 'bar'}, request_headers).body).to eq 'abc'
|
201
199
|
end
|
202
200
|
end
|
203
201
|
|
@@ -209,7 +207,7 @@ describe BooticClient::Client do
|
|
209
207
|
end
|
210
208
|
|
211
209
|
it 'POSTs request and parses response' do
|
212
|
-
expect(client.post(root_url, {foo: 'bar'}, request_headers).
|
210
|
+
expect(client.post(root_url, {foo: 'bar'}, request_headers).status).to eq 201
|
213
211
|
end
|
214
212
|
end
|
215
213
|
|
@@ -223,18 +221,19 @@ describe BooticClient::Client do
|
|
223
221
|
.to_return(status: 201, body: JSON.dump(root_data), headers: response_headers)
|
224
222
|
end
|
225
223
|
|
226
|
-
it 'POSTs request with base64-encoded file
|
227
|
-
|
224
|
+
it 'POSTs request with base64-encoded file' do
|
225
|
+
resp = client.post(root_url, {foo: 'bar', data: file}, request_headers)
|
226
|
+
expect(resp.status).to eq 201
|
228
227
|
end
|
229
228
|
|
230
229
|
it "works with anything that responds to #read" do
|
231
230
|
reader = double("reader", read: File.read(fixture_path("file.gif")))
|
232
|
-
expect(client.post(root_url, {foo: 'bar', data: reader}, request_headers).
|
231
|
+
expect(client.post(root_url, {foo: 'bar', data: reader}, request_headers).status).to eq 201
|
233
232
|
end
|
234
233
|
|
235
234
|
it "works with open-uri" do
|
236
235
|
reader = open(fixture_path("file.gif"))
|
237
|
-
expect(client.post(root_url, {foo: 'bar', data: reader}, request_headers).
|
236
|
+
expect(client.post(root_url, {foo: 'bar', data: reader}, request_headers).status).to eq 201
|
238
237
|
end
|
239
238
|
end
|
240
239
|
|
@@ -243,11 +242,13 @@ describe BooticClient::Client do
|
|
243
242
|
before do
|
244
243
|
stub_request(verb, root_url)
|
245
244
|
.with(body: JSON.dump({foo: 'bar'}), headers: request_headers)
|
246
|
-
.to_return(status: 200, body:
|
245
|
+
.to_return(status: 200, body: 'abc', headers: response_headers)
|
247
246
|
end
|
248
247
|
|
249
|
-
it "#{verb.to_s.upcase}s request
|
250
|
-
|
248
|
+
it "#{verb.to_s.upcase}s request" do
|
249
|
+
resp = client.send(verb, root_url, {foo: 'bar'}, request_headers)
|
250
|
+
expect(resp.status).to eq 200
|
251
|
+
expect(resp.body).to eq 'abc'
|
251
252
|
end
|
252
253
|
end
|
253
254
|
|
@@ -258,11 +259,13 @@ describe BooticClient::Client do
|
|
258
259
|
before do
|
259
260
|
stub_request(verb, root_url)
|
260
261
|
.with(body: JSON.dump({foo: 'bar', data: {name: 'la', file: base64_data}}), headers: request_headers)
|
261
|
-
.to_return(status: 200, body:
|
262
|
+
.to_return(status: 200, body: 'abc', headers: response_headers)
|
262
263
|
end
|
263
264
|
|
264
|
-
it "#{verb.to_s.upcase}s request with base64-encoded file data
|
265
|
-
|
265
|
+
it "#{verb.to_s.upcase}s request with base64-encoded file data" do
|
266
|
+
resp = client.send(verb, root_url, {foo: 'bar', data: {name: 'la', file: file}}, request_headers)
|
267
|
+
expect(resp.status).to eq 200
|
268
|
+
expect(resp.body).to eq 'abc'
|
266
269
|
end
|
267
270
|
end
|
268
271
|
end
|
data/spec/configuration_spec.rb
CHANGED
@@ -1,63 +1,75 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe BooticClient do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
describe BooticClient::Configuration do
|
4
|
+
context 'errors' do
|
5
|
+
it "raises if nil client_id" do
|
6
|
+
expect {
|
7
|
+
BooticClient.configure do |c|
|
8
|
+
c.client_id = nil
|
9
|
+
end
|
10
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
it "raises if nil client_secret" do
|
14
|
+
expect {
|
15
|
+
BooticClient.configure do |c|
|
16
|
+
c.client_secret = nil
|
17
|
+
end
|
18
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
it "raises if nil cache_store" do
|
22
|
+
expect {
|
23
|
+
BooticClient.configure do |c|
|
24
|
+
c.cache_store = nil
|
25
|
+
end
|
26
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
it "raises if nil or invalid auth_host" do
|
30
|
+
expect {
|
31
|
+
BooticClient.configure do |c|
|
32
|
+
c.auth_host = nil
|
33
|
+
end
|
34
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
expect {
|
37
|
+
BooticClient.configure do |c|
|
38
|
+
c.auth_host = 'not-a-url'
|
39
|
+
end
|
40
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
it "raises if nil or invalid api_root" do
|
44
|
+
expect {
|
45
|
+
BooticClient.configure do |c|
|
46
|
+
c.api_root = nil
|
47
|
+
end
|
48
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
expect {
|
51
|
+
BooticClient.configure do |c|
|
52
|
+
c.api_root = 'not-a-url'
|
53
|
+
end
|
54
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
55
|
+
end
|
56
|
+
|
57
|
+
it "raises if nil logger" do
|
58
|
+
expect {
|
59
|
+
BooticClient.configure do |c|
|
60
|
+
c.logger = nil
|
61
|
+
end
|
62
|
+
}.to raise_error BooticClient::InvalidConfigurationError
|
63
|
+
end
|
54
64
|
end
|
55
65
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
66
|
+
context 'instance' do
|
67
|
+
subject(:config) { described_class.new }
|
68
|
+
|
69
|
+
describe '#response_handlers' do
|
70
|
+
it 'includes Entity handler by default' do
|
71
|
+
expect(config.response_handlers.to_a.first).not_to be_nil
|
60
72
|
end
|
61
|
-
|
73
|
+
end
|
62
74
|
end
|
63
75
|
end
|
data/spec/entity_spec.rb
CHANGED
@@ -9,7 +9,8 @@ describe BooticClient::Entity do
|
|
9
9
|
'page' => 1,
|
10
10
|
'an_object' => {
|
11
11
|
'name' => 'Foobar',
|
12
|
-
'age' => 22
|
12
|
+
'age' => 22,
|
13
|
+
'another_object' => {'foo' => 'bar'}
|
13
14
|
},
|
14
15
|
'_links' => {
|
15
16
|
'self' => {'href' => '/foo'},
|
@@ -74,8 +75,11 @@ describe BooticClient::Entity do
|
|
74
75
|
end
|
75
76
|
|
76
77
|
it 'wraps object properties as entities' do
|
78
|
+
expect(entity.an_object).to be_a described_class
|
77
79
|
expect(entity.an_object.name).to eql('Foobar')
|
78
80
|
expect(entity.an_object.age).to eql(22)
|
81
|
+
expect(entity.an_object.another_object).to be_a described_class
|
82
|
+
expect(entity.an_object.another_object.foo).to eq 'bar'
|
79
83
|
end
|
80
84
|
|
81
85
|
it 'has a #properties object' do
|
@@ -160,7 +164,7 @@ describe BooticClient::Entity do
|
|
160
164
|
let(:next_page) { BooticClient::Entity.new({'page' => 2}, client) }
|
161
165
|
|
162
166
|
it 'exposes link target resources as normal properties' do
|
163
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foo?page=2',
|
167
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foo?page=2', {}).and_return next_page
|
164
168
|
entity.next.tap do |next_entity|
|
165
169
|
expect(next_entity).to be_kind_of(BooticClient::Entity)
|
166
170
|
expect(next_entity.page).to eql(2)
|
@@ -168,7 +172,7 @@ describe BooticClient::Entity do
|
|
168
172
|
end
|
169
173
|
|
170
174
|
it 'takes optional URI parameters' do
|
171
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/search?q=foo',
|
175
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/search?q=foo', {}).and_return next_page
|
172
176
|
entity.search(q: 'foo').tap do |next_entity|
|
173
177
|
expect(next_entity).to be_kind_of(BooticClient::Entity)
|
174
178
|
expect(next_entity.page).to eql(2)
|
@@ -222,8 +226,8 @@ describe BooticClient::Entity do
|
|
222
226
|
let(:page_2) { BooticClient::Entity.new(page_2_data, client) }
|
223
227
|
|
224
228
|
it 'lazily enumerates entries across pages, making as little requests as possible' do
|
225
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foo?page=2',
|
226
|
-
expect(client).to_not receive(:request_and_wrap).with(:get, '/foo?page=3',
|
229
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foo?page=2', {}).and_return page_2
|
230
|
+
expect(client).to_not receive(:request_and_wrap).with(:get, '/foo?page=3', {})
|
227
231
|
results = entity.full_set.first(4)
|
228
232
|
titles = results.map(&:title)
|
229
233
|
expect(titles).to match_array(['iPhone 4', 'iPhone 5', 'Item 3', 'Item 4'])
|
data/spec/relation_spec.rb
CHANGED
@@ -26,7 +26,7 @@ describe BooticClient::Relation do
|
|
26
26
|
|
27
27
|
describe 'running GET by default' do
|
28
28
|
it 'fetches data and returns entity' do
|
29
|
-
allow(client).to receive(:request_and_wrap).with(:get, '/foo/bars',
|
29
|
+
allow(client).to receive(:request_and_wrap).with(:get, '/foo/bars', {}).and_return entity
|
30
30
|
expect(relation.run).to eql(entity)
|
31
31
|
end
|
32
32
|
|
@@ -42,7 +42,7 @@ describe BooticClient::Relation do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'passes query string to client' do
|
45
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foos/bar',
|
45
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foos/bar', id: 2, q: 'test', page: 2).and_return entity
|
46
46
|
expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
|
47
47
|
end
|
48
48
|
end
|
@@ -61,7 +61,7 @@ describe BooticClient::Relation do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
it 'works with defaults' do
|
64
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foos/123',
|
64
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foos/123', {}).and_return entity
|
65
65
|
expect(relation.run(id: 123)).to eql(entity)
|
66
66
|
end
|
67
67
|
|
@@ -70,7 +70,7 @@ describe BooticClient::Relation do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'interpolates tokens' do
|
73
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=2',
|
73
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=2', {}).and_return entity
|
74
74
|
expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
|
75
75
|
end
|
76
76
|
|
@@ -92,7 +92,7 @@ describe BooticClient::Relation do
|
|
92
92
|
client,
|
93
93
|
)
|
94
94
|
|
95
|
-
expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=3',
|
95
|
+
expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=3', {foo: 1}).and_return entity
|
96
96
|
|
97
97
|
relation.run(id: 2, q: 'test', page: 3, foo: 1)
|
98
98
|
|
@@ -106,12 +106,12 @@ describe BooticClient::Relation do
|
|
106
106
|
let(:relation_templated) { BooticClient::Relation.new({'href' => '/foo/{bars}', 'templated' => true, 'type' => 'application/json', 'name' => 'self', 'method' => 'post'}, client) }
|
107
107
|
|
108
108
|
it 'POSTS data and returns resulting entity' do
|
109
|
-
allow(client).to receive(:request_and_wrap).with(:post, '/foo/bars',
|
109
|
+
allow(client).to receive(:request_and_wrap).with(:post, '/foo/bars', {}).and_return entity
|
110
110
|
expect(relation.run).to eql(entity)
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'interpolates templated URLs and sends remaining as BODY' do
|
114
|
-
allow(client).to receive(:request_and_wrap).with(:post, '/foo/123',
|
114
|
+
allow(client).to receive(:request_and_wrap).with(:post, '/foo/123', {foo: 'bar'}).and_return entity
|
115
115
|
expect(relation_templated.run(bars: 123, foo: 'bar')).to eql(entity)
|
116
116
|
end
|
117
117
|
end
|
@@ -120,7 +120,7 @@ describe BooticClient::Relation do
|
|
120
120
|
let(:relation) { BooticClient::Relation.new({'href' => '/foo/bars', 'type' => 'application/json', 'name' => 'self', 'method' => 'delete'}, client) }
|
121
121
|
|
122
122
|
it 'DELETEs data and returns resulting entity' do
|
123
|
-
allow(client).to receive(:request_and_wrap).with(:delete, '/foo/bars',
|
123
|
+
allow(client).to receive(:request_and_wrap).with(:delete, '/foo/bars', {}).and_return entity
|
124
124
|
expect(relation.run).to eql(entity)
|
125
125
|
end
|
126
126
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'bootic_client/response_handlers'
|
3
|
+
|
4
|
+
describe BooticClient::ResponseHandlers::Set do
|
5
|
+
let(:h1) do
|
6
|
+
Proc.new do |resp, _client|
|
7
|
+
if resp.headers['Content-Type'] =~ /json/
|
8
|
+
'H1'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
let(:h2) do
|
13
|
+
Proc.new do |resp, _client|
|
14
|
+
if resp.headers['Content-Type'] =~ /text/
|
15
|
+
'H2'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
let(:h3) do
|
20
|
+
Proc.new do |resp, _client|
|
21
|
+
if resp.headers['Content-Type'] =~ /json/
|
22
|
+
'H3'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'initializes with default handlers' do
|
28
|
+
set = described_class.new([h1])
|
29
|
+
expect(set.to_a).to eq [h1]
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#resolve' do
|
33
|
+
it 'finds first matching handler and returns result' do
|
34
|
+
set = described_class.new([h1, h2, h3])
|
35
|
+
|
36
|
+
text_resp = instance_double(::Faraday::Response, headers: {'Content-Type' => 'text/plain'})
|
37
|
+
expect(set.resolve(text_resp, nil)).to eq 'H2'
|
38
|
+
|
39
|
+
json_resp = instance_double(::Faraday::Response, headers: {'Content-Type' => 'application/json'})
|
40
|
+
expect(set.resolve(json_resp, nil)).to eq 'H1'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns raw response if no handler found' do
|
44
|
+
set = described_class.new([h1, h2, h3])
|
45
|
+
img_resp = instance_double(::Faraday::Response, headers: {'Content-Type' => 'image/jpeg'})
|
46
|
+
expect(set.resolve(img_resp, nil)).to eq img_resp
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#append' do
|
51
|
+
it 'adds handlers' do
|
52
|
+
set = described_class.new
|
53
|
+
|
54
|
+
text_resp = instance_double(::Faraday::Response, headers: {'Content-Type' => 'text/plain'})
|
55
|
+
expect(set.resolve(text_resp, nil)).to eq text_resp
|
56
|
+
|
57
|
+
set.append(h2)
|
58
|
+
expect(set.resolve(text_resp, nil)).to eq 'H2'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#prepend' do
|
63
|
+
it 'prepends handlers' do
|
64
|
+
set = described_class.new([h1, h2])
|
65
|
+
|
66
|
+
json_resp = instance_double(::Faraday::Response, headers: {'Content-Type' => 'application/json'})
|
67
|
+
expect(set.resolve(json_resp, nil)).to eq 'H1'
|
68
|
+
|
69
|
+
set.prepend(h3)
|
70
|
+
expect(set.resolve(json_resp, nil)).to eq 'H3'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'bootic_client/strategies/strategy'
|
3
|
+
|
4
|
+
describe BooticClient::Strategies::Strategy do
|
5
|
+
require 'webmock/rspec'
|
6
|
+
|
7
|
+
let(:config) { BooticClient::Configuration.new }
|
8
|
+
subject(:strategy) { described_class.new(config) }
|
9
|
+
|
10
|
+
describe '#request_and_wrap' do
|
11
|
+
context 'response is JSON' do
|
12
|
+
let(:resp_data) do
|
13
|
+
{
|
14
|
+
'name' => 'Jason'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
stub_request(:get, 'https://a.server.com/foo')
|
20
|
+
.to_return(status: 200, body: JSON.dump(resp_data), headers: {'Content-Type' => 'application/json'})
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the raw response' do
|
24
|
+
resp = strategy.request_and_wrap(:get, 'https://a.server.com/foo')
|
25
|
+
expect(resp).to be_a(BooticClient::Entity)
|
26
|
+
expect(resp.name).to eq 'Jason'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'response type is not handled' do
|
31
|
+
before do
|
32
|
+
stub_request(:get, 'https://a.server.com/foo')
|
33
|
+
.to_return(status: 200, body: 'abc', headers: {'Content-Type' => 'text/plain'})
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns the raw response' do
|
37
|
+
resp = strategy.request_and_wrap(:get, 'https://a.server.com/foo')
|
38
|
+
expect(resp).to be_a(Faraday::Response)
|
39
|
+
expect(resp.body).to eq 'abc'
|
40
|
+
expect(resp.status).to eq 200
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'uses available request handlers' do
|
44
|
+
custom_resp = Struct.new(:message)
|
45
|
+
|
46
|
+
config.response_handlers.append(Proc.new { |resp, client|
|
47
|
+
if resp.headers['Content-Type'] == 'text/plain'
|
48
|
+
custom_resp.new(resp.body)
|
49
|
+
end
|
50
|
+
})
|
51
|
+
|
52
|
+
resp = strategy.request_and_wrap(:get, 'https://a.server.com/foo')
|
53
|
+
expect(resp).to be_a custom_resp
|
54
|
+
expect(resp.message).to eq 'abc'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'response is an image' do
|
59
|
+
before do
|
60
|
+
stub_request(:get, 'https://a.server.com/a/b/foo.jpg')
|
61
|
+
.to_return(status: 200, body: 'abc', headers: {'Content-Type' => 'image/jpeg'})
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns an IO-like object' do
|
65
|
+
img = strategy.request_and_wrap(:get, 'https://a.server.com/a/b/foo.jpg')
|
66
|
+
expect(img.io).to be_a StringIO
|
67
|
+
expect(img.read).to eq 'abc'
|
68
|
+
expect(img.file_name).to eq 'foo.jpg'
|
69
|
+
expect(img.mime_type).to eq 'image/jpeg'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bootic_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ismael Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -183,9 +183,11 @@ files:
|
|
183
183
|
- bootic_client.gemspec
|
184
184
|
- lib/bootic_client.rb
|
185
185
|
- lib/bootic_client/client.rb
|
186
|
+
- lib/bootic_client/configuration.rb
|
186
187
|
- lib/bootic_client/entity.rb
|
187
188
|
- lib/bootic_client/errors.rb
|
188
189
|
- lib/bootic_client/relation.rb
|
190
|
+
- lib/bootic_client/response_handlers.rb
|
189
191
|
- lib/bootic_client/stores/memcache.rb
|
190
192
|
- lib/bootic_client/strategies/authorized.rb
|
191
193
|
- lib/bootic_client/strategies/basic_auth.rb
|
@@ -206,7 +208,9 @@ files:
|
|
206
208
|
- spec/fixtures/file.gif
|
207
209
|
- spec/memcache_storage_spec.rb
|
208
210
|
- spec/relation_spec.rb
|
211
|
+
- spec/response_handlers_spec.rb
|
209
212
|
- spec/spec_helper.rb
|
213
|
+
- spec/strategy_spec.rb
|
210
214
|
- spec/whiny_uri_spec.rb
|
211
215
|
homepage: https://developers.bootic.net
|
212
216
|
licenses:
|
@@ -228,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
228
232
|
version: '0'
|
229
233
|
requirements: []
|
230
234
|
rubyforge_project:
|
231
|
-
rubygems_version: 2.
|
235
|
+
rubygems_version: 2.7.7
|
232
236
|
signing_key:
|
233
237
|
specification_version: 4
|
234
238
|
summary: Official Ruby client for the Bootic API
|
@@ -244,5 +248,7 @@ test_files:
|
|
244
248
|
- spec/fixtures/file.gif
|
245
249
|
- spec/memcache_storage_spec.rb
|
246
250
|
- spec/relation_spec.rb
|
251
|
+
- spec/response_handlers_spec.rb
|
247
252
|
- spec/spec_helper.rb
|
253
|
+
- spec/strategy_spec.rb
|
248
254
|
- spec/whiny_uri_spec.rb
|