bootic_client 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 03f3eb030bbf24bfb6139b46682376a00520cff4
4
- data.tar.gz: 480c44fe0b9e62387028d5d0d2061ee5350664e7
2
+ SHA256:
3
+ metadata.gz: 30679ee6a43b99369706f814812e081c631f7fb430ee1aee257f39690dd065bd
4
+ data.tar.gz: 5edc48fe9a7f34e4adb0cd2eeab702953b7371d29ff538fb7a2c629ebd74d29c
5
5
  SHA512:
6
- metadata.gz: 29a90003594b260e0dbc0a0ddcdaa2758ab9f54a87fd467698bc7a658efaa836ebeb5a3182f24c83e659016c753c669970a5178ca5224e528a6ed801b402b3aa
7
- data.tar.gz: ea07a9a75c125f616945985be788b5b246e53c4df9e4b288a2e70d41445c501a1df943f79071f7d6c31a34652e5a3d743b5d3a9653c54d3d9157f312fee3e1d8
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
@@ -5,5 +5,5 @@ gemspec
5
5
 
6
6
  group :test do
7
7
  gem 'byebug' if RUBY_VERSION.to_i >= 2
8
- gem 'webmock', '1.22.3'
8
+ gem 'webmock', '3.5.1'
9
9
  end
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.
@@ -60,7 +60,7 @@ module BooticClient
60
60
  end
61
61
  end
62
62
 
63
- protected
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
@@ -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
- OpenStruct.new(obj)
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
- protected
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, entity_class: Entity, complain_on_undeclared_params: self.class.complain_on_undeclared_params)
22
- @attrs, @client, @entity_class = attrs, client, entity_class
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), entity_class, payload
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, entity_class, opts
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 :entity_class, :client, :attrs, :complain_on_undeclared_params
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
- protected
7
+ private
8
8
 
9
9
  def validate!
10
- raise ArgumentError, "options MUST include access_token" unless options[:access_token]
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
- protected
11
+ private
12
12
 
13
13
  def validate!
14
- raise ArgumentError, "options MUST include username" unless options[:username]
15
- raise ArgumentError, "options MUST include password" unless options[:password]
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
@@ -7,7 +7,7 @@ module BooticClient
7
7
  private
8
8
 
9
9
  def validate!
10
- raise ArgumentError, "options MUST include access_token" unless options[:access_token]
10
+ raise ArgumentError, 'options MUST include access_token' unless options[:access_token]
11
11
  end
12
12
 
13
13
  def request_headers
@@ -4,7 +4,7 @@ module BooticClient
4
4
  module Strategies
5
5
 
6
6
  class ClientCredentials < Oauth2Strategy
7
- protected
7
+ private
8
8
 
9
9
  def get_token
10
10
  opts = {}
@@ -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
- protected
13
+ private
14
14
 
15
15
  def validate!
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
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, Entity
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, wrapper_class = Entity)
21
- request_and_wrap :get, url, wrapper_class
21
+ def from_url(url)
22
+ request_and_wrap :get, url
22
23
  end
23
24
 
24
- def request_and_wrap(request_method, href, wrapper_class, payload = {})
25
+ def request_and_wrap(request_method, href, payload = {})
25
26
  pre_flight
26
27
  retryable do
27
- wrapper_class.new client.send(request_method, href, payload, request_headers).body, self
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
 
@@ -1,3 +1,3 @@
1
1
  module BooticClient
2
- VERSION = "0.0.21".freeze
2
+ VERSION = "0.0.22".freeze
3
3
  end
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 self, opts, &on_new_token
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 self
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 check_url!(name, v)
84
- raise InvalidConfigurationError, "#{name} must be a valid URL" unless v.to_s =~ VERY_BASIC_URL_CHECK
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://foo:bar@api.bootic.net/v1')
38
- .to_return(status: 401, body: JSON.dump(root_data))
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://foo:bar@api.bootic.net/v1')
50
- .to_return(status: 200, body: JSON.dump(root_data))
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://foo:bar@api.bootic.net/v1/products/1')
55
- .to_return(status: 200, body: JSON.dump(product_data))
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.tap do |b|
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: JSON.dump(root_data), headers: response_headers)
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['message']).to eql('Hello!')
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).body['message']).to eql('Hello!')
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 and parses response' do
227
- expect(client.post(root_url, {foo: 'bar', data: file}, request_headers).body['message']).to eql('Hello!')
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).body['message']).to eql('Hello!')
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).body['message']).to eql('Hello!')
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: JSON.dump(root_data), headers: response_headers)
245
+ .to_return(status: 200, body: 'abc', headers: response_headers)
247
246
  end
248
247
 
249
- it "#{verb.to_s.upcase}s request and parses response" do
250
- expect(client.send(verb, root_url, {foo: 'bar'}, request_headers).body['message']).to eql('Hello!')
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: JSON.dump(root_data), headers: response_headers)
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 and parses response" do
265
- expect(client.send(verb, root_url, {foo: 'bar', data: {name: 'la', file: file}}, request_headers).body['message']).to eql('Hello!')
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
@@ -1,63 +1,75 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe BooticClient do
4
- it "raises if nil client_id" do
5
- expect {
6
- BooticClient.configure do |c|
7
- c.client_id = nil
8
- end
9
- }.to raise_error BooticClient::InvalidConfigurationError
10
- end
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
- it "raises if nil client_secret" do
13
- expect {
14
- BooticClient.configure do |c|
15
- c.client_secret = nil
16
- end
17
- }.to raise_error BooticClient::InvalidConfigurationError
18
- end
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
- it "raises if nil cache_store" do
21
- expect {
22
- BooticClient.configure do |c|
23
- c.cache_store = nil
24
- end
25
- }.to raise_error BooticClient::InvalidConfigurationError
26
- end
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
- it "raises if nil or invalid auth_host" do
29
- expect {
30
- BooticClient.configure do |c|
31
- c.auth_host = nil
32
- end
33
- }.to raise_error BooticClient::InvalidConfigurationError
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
- expect {
36
- BooticClient.configure do |c|
37
- c.auth_host = 'not-a-url'
38
- end
39
- }.to raise_error BooticClient::InvalidConfigurationError
40
- end
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
- it "raises if nil or invalid api_root" do
43
- expect {
44
- BooticClient.configure do |c|
45
- c.api_root = nil
46
- end
47
- }.to raise_error BooticClient::InvalidConfigurationError
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
- expect {
50
- BooticClient.configure do |c|
51
- c.api_root = 'not-a-url'
52
- end
53
- }.to raise_error BooticClient::InvalidConfigurationError
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
- it "raises if nil logger" do
57
- expect {
58
- BooticClient.configure do |c|
59
- c.logger = nil
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
- }.to raise_error BooticClient::InvalidConfigurationError
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', BooticClient::Entity, {}).and_return next_page
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', BooticClient::Entity, {}).and_return next_page
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', BooticClient::Entity, {}).and_return page_2
226
- expect(client).to_not receive(:request_and_wrap).with(:get, '/foo?page=3', BooticClient::Entity, {})
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'])
@@ -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', BooticClient::Entity, {}).and_return entity
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', BooticClient::Entity, id: 2, q: 'test', page: 2).and_return entity
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', BooticClient::Entity, {}).and_return entity
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', BooticClient::Entity, {}).and_return entity
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', BooticClient::Entity, {foo: 1}).and_return entity
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', BooticClient::Entity, {}).and_return entity
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', BooticClient::Entity, {foo: 'bar'}).and_return entity
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', BooticClient::Entity, {}).and_return entity
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.21
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: 2018-08-30 00:00:00.000000000 Z
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.6.13
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