bootic_client 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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