bootic_client 0.0.3 → 0.0.4

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
2
  SHA1:
3
- metadata.gz: 727d4868928f07359322ccc49dfed3d20edfae0a
4
- data.tar.gz: 7626595ffbef58af0b052b6a74c3dc220b3e32ca
3
+ metadata.gz: 7f0b175f26ae3c07540c632a0e07488ab48256a2
4
+ data.tar.gz: 6dfc0cc96fdadce33457631b507ea355b0eefff9
5
5
  SHA512:
6
- metadata.gz: 56d7d5c1c16e19f61f5d9e59de8b494f3ba20f8510c7eaba5d21a1d2aeab1a97eaf125c80c5923b524dd422c6f75904ddb5f20fd3c98f4d52765dce18e2e1071
7
- data.tar.gz: 8fb91e3fcfbed8a09bf3903e3952f9078554b381d657eec9d92b08b1e955741a40c5e3c46b2f67dada5f3d0cac45feb1a337d2536c25a762606835a27af2ef94
6
+ metadata.gz: cff8a48dc27c6b5362df02749e63de27258ee8cf58091ee9bf3cac17079eea3a21c138a16245f16b96d5b2e22215411e97a5486c299944197fe0d8a2e66e8aa7
7
+ data.tar.gz: c82c7be167dd5519bc7750a60dabf4d0af95c2372f284817ace9d9e4a508216a0de8f4fbd0523ca6e3a288a9b0aef93c44e4d71a1a51276dac731ab7b78fabee
data/README.md CHANGED
@@ -127,7 +127,7 @@ All resource link relations include a "docs" URL so you can learn more about tha
127
127
 
128
128
  ```ruby
129
129
  shop = root.shops.first
130
- puts shop.rels[:create_product] # => 'https://developers.bootic.net/rels/create_product'
130
+ puts shop.rels[:create_product].docs # => 'https://developers.bootic.net/rels/create_product'
131
131
  ```
132
132
 
133
133
  ## Cache storage
@@ -11,10 +11,9 @@ module BooticClient
11
11
  USER_AGENT = "[BooticClient v#{VERSION}] Ruby-#{RUBY_VERSION} - #{RUBY_PLATFORM}".freeze
12
12
  JSON_MIME = 'application/json'.freeze
13
13
 
14
- attr_reader :options, :api_root
14
+ attr_reader :options
15
15
 
16
- def initialize(api_root, options = {}, &block)
17
- @api_root = api_root
16
+ def initialize(options = {}, &block)
18
17
  @options = {
19
18
  access_token: nil,
20
19
  logging: false
@@ -25,40 +24,38 @@ module BooticClient
25
24
  conn &block if block_given?
26
25
  end
27
26
 
28
- def get_and_wrap(href, wrapper_class, query = {})
29
- wrapper_class.new get(href, query).body, self
27
+ def get(href, query = {})
28
+ validated_request!(:get, href) do |req|
29
+ req.params.update(query)
30
+ end
30
31
  end
31
32
 
32
- def post_and_wrap(href, wrapper_class, payload = {})
33
- wrapper_class.new post(href, payload).body, self
33
+ def post(href, payload = {})
34
+ validated_request!(:post, href) do |req|
35
+ req.body = JSON.dump(payload)
36
+ end
34
37
  end
35
38
 
36
- def get(href, query = {})
37
- validated! do
38
- conn.get do |req|
39
- req.url href
40
- req.headers.update request_headers
41
- req.params.update(query)
42
- end
39
+ def put(href, payload = {})
40
+ validated_request!(:put, href) do |req|
41
+ req.body = JSON.dump(payload)
43
42
  end
44
43
  end
45
44
 
46
- def post(href, payload = {})
47
- validated! do
48
- conn.post do |req|
49
- req.url href
50
- req.headers.update request_headers
51
- req.headers['Accept'] = JSON_MIME
52
- req.headers['Content-Type'] = JSON_MIME
53
- req.body = JSON.dump(payload)
54
- end
45
+ def patch(href, payload = {})
46
+ validated_request!(:patch, href) do |req|
47
+ req.body = JSON.dump(payload)
55
48
  end
56
49
  end
57
50
 
51
+ def delete(href, query = {})
52
+ validated_request!(:delete, href)
53
+ end
54
+
58
55
  protected
59
56
 
60
57
  def conn(&block)
61
- @conn ||= Faraday.new(url: api_root) do |f|
58
+ @conn ||= Faraday.new do |f|
62
59
  cache_options = {shared_cache: false, store: options[:cache_store]}
63
60
  cache_options[:logger] = options[:logger] if options[:logging]
64
61
 
@@ -73,13 +70,20 @@ module BooticClient
73
70
  def request_headers
74
71
  {
75
72
  'Authorization' => "Bearer #{options[:access_token]}",
76
- 'User-Agent' => USER_AGENT
73
+ 'User-Agent' => USER_AGENT,
74
+ 'Accept' => JSON_MIME,
75
+ 'Content-Type' => JSON_MIME
77
76
  }
78
77
  end
79
78
 
80
- def validated!(&block)
79
+ def validated_request!(verb, href, &block)
81
80
  validate_request!
82
- resp = yield
81
+ resp = conn.send(verb) do |req|
82
+ req.url href
83
+ req.headers.update request_headers
84
+ yield req if block_given?
85
+ end
86
+
83
87
  raise_if_invalid! resp
84
88
  resp
85
89
  end
@@ -96,4 +100,4 @@ module BooticClient
96
100
  end
97
101
  end
98
102
 
99
- end
103
+ end
@@ -44,21 +44,13 @@ module BooticClient
44
44
  end
45
45
 
46
46
  def run(opts = {})
47
- self.send(transport_method, opts)
48
- end
49
-
50
- def get(opts = {})
51
47
  if templated?
52
- client.get_and_wrap uri.expand(opts), wrapper_class
48
+ client.request_and_wrap transport_method.to_sym, uri.expand(opts), wrapper_class, opts
53
49
  else
54
- client.get_and_wrap href, wrapper_class, opts
50
+ client.request_and_wrap transport_method.to_sym, href, wrapper_class, opts
55
51
  end
56
52
  end
57
53
 
58
- def post(opts = {})
59
- client.post_and_wrap href, wrapper_class, opts
60
- end
61
-
62
54
  def self.expand(href, opts = {})
63
55
  URITemplate.new(href).expand(opts)
64
56
  end
@@ -71,4 +63,4 @@ module BooticClient
71
63
  end
72
64
  end
73
65
 
74
- end
66
+ end
@@ -13,17 +13,17 @@ module BooticClient
13
13
  end
14
14
 
15
15
  def root
16
- get config.api_root
16
+ request_and_wrap :get, config.api_root, Entity
17
17
  end
18
18
 
19
- def get(href, query = {})
19
+ def request_and_wrap(request_method, href, wrapper_class, payload = {})
20
20
  begin
21
- client.get_and_wrap(href, Entity, query)
21
+ wrapper_class.new client.send(request_method, href, payload).body, self
22
22
  rescue TokenError => e
23
23
  new_token = get_token
24
24
  client.options[:access_token] = new_token
25
25
  on_new_token.call new_token
26
- client.get_and_wrap(href, Entity, query)
26
+ wrapper_class.new client.send(request_method, href, payload).body, self
27
27
  end
28
28
  end
29
29
 
@@ -52,8 +52,8 @@ module BooticClient
52
52
  end
53
53
 
54
54
  def client
55
- @client ||= Client.new(config.api_root, options)
55
+ @client ||= Client.new(options)
56
56
  end
57
57
  end
58
58
  end
59
- end
59
+ end
@@ -1,3 +1,3 @@
1
1
  module BooticClient
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -18,7 +18,7 @@ describe 'BooticClient::Strategies::Authorized' do
18
18
 
19
19
  def stub_api_root(access_token, status, body)
20
20
  stub_request(:get, "https://api.bootic.net/v1").
21
- with(headers: {'Accept'=>'*/*', 'Authorization' => "Bearer #{access_token}"}).
21
+ with(headers: {'Accept'=>'application/json', 'Authorization' => "Bearer #{access_token}"}).
22
22
  to_return(status: status, :body => JSON.dump(body))
23
23
  end
24
24
 
@@ -45,7 +45,7 @@ describe 'BooticClient::Strategies::Authorized' do
45
45
  let(:root_data) {
46
46
  {
47
47
  '_links' => {
48
- 'shops' => {'href' => 'https://api.bootic.net/v1/products'}
48
+ 'shops' => {'href' => 'https://api.bootic.net/v1/shops'}
49
49
  },
50
50
  'message' => "Hello!"
51
51
  }
@@ -109,7 +109,7 @@ describe 'BooticClient::Strategies::Authorized' do
109
109
  @successful_root_request = stub_api_root('foobar', 200, root_data)
110
110
  end
111
111
 
112
- it 'attempts unauthorised API request, refreshes token from auth an tries again' do
112
+ it 'attempts unauthorised API request, refreshes token from auth and tries again' do
113
113
  root = client.root
114
114
  expect(@failed_root_request).to have_been_requested
115
115
  expect(@auth_request).to have_been_requested
@@ -121,5 +121,28 @@ describe 'BooticClient::Strategies::Authorized' do
121
121
  expect(store[:access_token]).to eql('foobar')
122
122
  end
123
123
  end
124
+
125
+ context 'expired token, other resources' do
126
+ before do
127
+ stub_api_root('abc', 200, root_data)
128
+ @unauthorized_request = stub_request(:get, "https://api.bootic.net/v1/shops").
129
+ with(headers: {'Accept'=>'application/json', 'Authorization' => "Bearer abc"}).
130
+ to_return(status: 401, :body => JSON.dump(message: 'authorized'))
131
+ @auth_request = stub_auth('abc', 200, access_token: 'validtoken')
132
+
133
+ @authorized_request = stub_request(:get, "https://api.bootic.net/v1/shops").
134
+ with(headers: {'Accept'=>'application/json', 'Authorization' => "Bearer validtoken"}).
135
+ to_return(status: 200, :body => JSON.dump(title: 'All shops'))
136
+ @root = client.root
137
+ end
138
+
139
+ it 'attempts unauthorized API request to shops, refreshes token and tries again' do
140
+ shops = @root.shops
141
+ expect(@unauthorized_request).to have_been_requested
142
+ expect(@auth_request).to have_been_requested
143
+ expect(@authorized_request).to have_been_requested
144
+ expect(shops.title).to eql('All shops')
145
+ end
146
+ end
124
147
  end
125
- end
148
+ end
@@ -32,7 +32,7 @@ describe 'BooticClient::Strategies::ClientCredentials' do
32
32
 
33
33
  def stub_api_root(access_token, status, body)
34
34
  stub_request(:get, "https://api.bootic.net/v1").
35
- with(headers: {'Accept'=>'*/*', 'Authorization' => "Bearer #{access_token}"}).
35
+ with(headers: {'Accept'=>'application/json', 'Authorization'=>"Bearer #{access_token}"}).
36
36
  to_return(status: status, :body => JSON.dump(body))
37
37
  end
38
38
 
@@ -94,4 +94,4 @@ describe 'BooticClient::Strategies::ClientCredentials' do
94
94
  end
95
95
  end
96
96
 
97
- end
97
+ end
@@ -6,7 +6,10 @@ describe BooticClient::Client do
6
6
 
7
7
  describe 'valid response' do
8
8
  let(:root_url) { 'https://api.bootic.net/v1' }
9
- let(:client) { BooticClient::Client.new(root_url, access_token: 'xxx') }
9
+ let(:client) { BooticClient::Client.new(access_token: 'xxx') }
10
+ let(:request_headers) {
11
+ {'Accept' => 'application/json', 'Authorization' => "Bearer xxx"}
12
+ }
10
13
  let(:response_headers) {
11
14
  {'Content-Type' => 'application/json', 'Last-Modified' => 'Sat, 07 Jun 2014 12:10:33 GMT'}
12
15
  }
@@ -60,7 +63,7 @@ describe BooticClient::Client do
60
63
  describe 'no access token' do
61
64
  it 'raises error' do
62
65
  expect{
63
- BooticClient::Client.new(root_url).get(root_url)
66
+ BooticClient::Client.new.get(root_url)
64
67
  }.to raise_error(BooticClient::NoAccessTokenError)
65
68
  end
66
69
  end
@@ -120,35 +123,61 @@ describe BooticClient::Client do
120
123
 
121
124
  end
122
125
 
123
- describe '#get_and_wrap' do
124
- before do
125
- stub_request(:get, root_url)
126
- .with(query: {foo: 'bar'})
127
- .to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
126
+ context 'HTTP verbs' do
127
+ describe 'GET' do
128
+
129
+ before do
130
+ stub_request(:get, root_url)
131
+ .with(query: {foo: 'bar'}, headers: request_headers)
132
+ .to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
133
+ end
134
+
135
+ it 'GETs response' do
136
+ expect(client.get(root_url, foo: 'bar').body['message']).to eql('Hello!')
137
+ end
128
138
  end
129
139
 
130
- it 'wraps JSON response in entity' do
131
- wrapper = double('Wrapper Class')
132
- entity = double('Entity')
133
- expect(wrapper).to receive(:new).with(root_data, client).and_return entity
134
- expect(client.get_and_wrap(root_url, wrapper, foo: 'bar')).to eql(entity)
140
+ describe 'POST' do
141
+ before do
142
+ stub_request(:post, root_url)
143
+ .with(body: JSON.dump({foo: 'bar'}), headers: request_headers)
144
+ .to_return(status: 201, body: JSON.dump(root_data), headers: response_headers)
145
+ end
146
+
147
+ it 'POSTs request and parses response' do
148
+ expect(client.post(root_url, foo: 'bar').body['message']).to eql('Hello!')
149
+ end
135
150
  end
136
- end
151
+
152
+ [:put, :patch].each do |verb|
153
+ describe verb.to_s.upcase do
154
+ before do
155
+ stub_request(verb, root_url)
156
+ .with(body: JSON.dump({foo: 'bar'}), headers: request_headers)
157
+ .to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
158
+ end
137
159
 
138
- describe '#post_and_wrap' do
139
- before do
140
- stub_request(:post, root_url)
141
- .with(body: JSON.dump({foo: 'bar'}), headers: {'Accept' => 'application/json', 'Content-Type' => 'application/json'})
142
- .to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
160
+ it "#{verb.to_s.upcase}s request and parses response" do
161
+ expect(client.send(verb, root_url, foo: 'bar').body['message']).to eql('Hello!')
162
+ end
163
+ end
143
164
  end
165
+
166
+ context 'DELETE' do
167
+ before do
168
+ @delete_requst = stub_request(:delete, root_url)
169
+ .with(headers: request_headers)
170
+ .to_return(status: 200, body: JSON.dump(root_data), headers: response_headers)
171
+ end
144
172
 
145
- it 'wraps JSON response in entity' do
146
- wrapper = double('Wrapper Class')
147
- entity = double('Entity')
148
- expect(wrapper).to receive(:new).with(root_data, client).and_return entity
149
- expect(client.post_and_wrap(root_url, wrapper, foo: 'bar')).to eql(entity)
173
+ it 'DELETEs request and parses response' do
174
+ expect(client.send(:delete, root_url).status).to eql(200)
175
+ expect(@delete_requst).to have_been_requested
176
+ end
150
177
  end
178
+
151
179
  end
152
180
 
181
+
153
182
  end
154
- end
183
+ end
@@ -139,7 +139,7 @@ describe BooticClient::Entity do
139
139
  let(:next_page) { BooticClient::Entity.new({'page' => 2}, client) }
140
140
 
141
141
  it 'exposes link target resources as normal properties' do
142
- expect(client).to receive(:get_and_wrap).with('/foo?page=2', BooticClient::Entity, {}).and_return next_page
142
+ expect(client).to receive(:request_and_wrap).with(:get, '/foo?page=2', BooticClient::Entity, {}).and_return next_page
143
143
  entity.next.tap do |next_entity|
144
144
  expect(next_entity).to be_kind_of(BooticClient::Entity)
145
145
  expect(next_entity.page).to eql(2)
@@ -147,7 +147,7 @@ describe BooticClient::Entity do
147
147
  end
148
148
 
149
149
  it 'takes optional URI parameters' do
150
- expect(client).to receive(:get_and_wrap).with('/search?q=foo', BooticClient::Entity).and_return next_page
150
+ expect(client).to receive(:request_and_wrap).with(:get, '/search?q=foo', BooticClient::Entity, {q: 'foo'}).and_return next_page
151
151
  entity.search(q: 'foo').tap do |next_entity|
152
152
  expect(next_entity).to be_kind_of(BooticClient::Entity)
153
153
  expect(next_entity.page).to eql(2)
@@ -18,7 +18,7 @@ describe BooticClient::Relation do
18
18
 
19
19
  describe 'running GET by default' do
20
20
  it 'fetches data and returns entity' do
21
- client.stub(:get_and_wrap).with('/foo/bars', BooticClient::Entity, {}).and_return entity
21
+ client.stub(:request_and_wrap).with(:get, '/foo/bars', BooticClient::Entity, {}).and_return entity
22
22
  expect(relation.run).to eql(entity)
23
23
  end
24
24
 
@@ -30,7 +30,7 @@ describe BooticClient::Relation do
30
30
  end
31
31
 
32
32
  it 'passes query string to client' do
33
- expect(client).to receive(:get_and_wrap).with('/foos/bar', BooticClient::Entity, id: 2, q: 'test', page: 2).and_return entity
33
+ expect(client).to receive(:request_and_wrap).with(:get, '/foos/bar', BooticClient::Entity, id: 2, q: 'test', page: 2).and_return entity
34
34
  expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
35
35
  end
36
36
  end
@@ -43,12 +43,12 @@ describe BooticClient::Relation do
43
43
  end
44
44
 
45
45
  it 'works with defaults' do
46
- expect(client).to receive(:get_and_wrap).with('/foos/', BooticClient::Entity).and_return entity
46
+ expect(client).to receive(:request_and_wrap).with(:get, '/foos/', BooticClient::Entity, {}).and_return entity
47
47
  expect(relation.run).to eql(entity)
48
48
  end
49
49
 
50
50
  it 'interpolates tokens' do
51
- expect(client).to receive(:get_and_wrap).with('/foos/2?q=test&page=2', BooticClient::Entity).and_return entity
51
+ expect(client).to receive(:request_and_wrap).with(:get, '/foos/2?q=test&page=2', BooticClient::Entity, {id:2,q:'test',page:2}).and_return entity
52
52
  expect(relation.run(id: 2, q: 'test', page: 2)).to eql(entity)
53
53
  end
54
54
  end
@@ -56,11 +56,17 @@ describe BooticClient::Relation do
56
56
 
57
57
  describe 'POST' do
58
58
  let(:relation) { BooticClient::Relation.new({'href' => '/foo/bars', 'type' => 'application/json', 'name' => 'self', 'method' => 'post'}, client) }
59
+ let(:relation_templated) { BooticClient::Relation.new({'href' => '/foo/{bars}', 'templated' => true, 'type' => 'application/json', 'name' => 'self', 'method' => 'post'}, client) }
59
60
 
60
61
  it 'POSTS data and returns resulting entity' do
61
- client.stub(:post_and_wrap).with('/foo/bars', BooticClient::Entity, {}).and_return entity
62
+ client.stub(:request_and_wrap).with(:post, '/foo/bars', BooticClient::Entity, {}).and_return entity
62
63
  expect(relation.run).to eql(entity)
63
64
  end
65
+
66
+ it 'interpolates templated URLs' do
67
+ client.stub(:request_and_wrap).with(:post, '/foo/123', BooticClient::Entity, {foo: 'bar', bars: 123}).and_return entity
68
+ expect(relation_templated.run(bars: 123, foo: 'bar')).to eql(entity)
69
+ end
64
70
  end
65
71
  end
66
72
  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.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Celis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-21 00:00:00.000000000 Z
11
+ date: 2014-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday