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 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